summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite.cpp43
-rw-r--r--scene/2d/animated_sprite.h6
-rw-r--r--scene/2d/audio_stream_player_2d.cpp69
-rw-r--r--scene/2d/audio_stream_player_2d.h6
-rw-r--r--scene/2d/back_buffer_copy.cpp5
-rw-r--r--scene/2d/back_buffer_copy.h1
-rw-r--r--scene/2d/canvas_item.cpp45
-rw-r--r--scene/2d/canvas_item.h39
-rw-r--r--scene/2d/collision_object_2d.cpp29
-rw-r--r--scene/2d/collision_object_2d.h4
-rw-r--r--scene/2d/collision_polygon_2d.cpp4
-rw-r--r--scene/2d/collision_shape_2d.cpp2
-rw-r--r--scene/2d/cpu_particles_2d.cpp1402
-rw-r--r--scene/2d/cpu_particles_2d.h289
-rw-r--r--scene/2d/joints_2d.cpp4
-rw-r--r--scene/2d/light_2d.cpp12
-rw-r--r--scene/2d/light_2d.h2
-rw-r--r--scene/2d/line_2d.cpp5
-rw-r--r--scene/2d/line_2d.h4
-rw-r--r--scene/2d/line_builder.cpp15
-rw-r--r--scene/2d/line_builder.h2
-rw-r--r--scene/2d/navigation2d.cpp51
-rw-r--r--scene/2d/navigation_polygon.cpp12
-rw-r--r--scene/2d/node_2d.cpp3
-rw-r--r--scene/2d/particles_2d.cpp27
-rw-r--r--scene/2d/particles_2d.h10
-rw-r--r--scene/2d/physics_body_2d.cpp498
-rw-r--r--scene/2d/physics_body_2d.h47
-rw-r--r--scene/2d/polygon_2d.cpp33
-rw-r--r--scene/2d/ray_cast_2d.cpp36
-rw-r--r--scene/2d/ray_cast_2d.h9
-rw-r--r--scene/2d/remote_transform_2d.cpp9
-rw-r--r--scene/2d/screen_button.cpp14
-rw-r--r--scene/2d/screen_button.h3
-rw-r--r--scene/2d/skeleton_2d.cpp14
-rw-r--r--scene/2d/sprite.cpp49
-rw-r--r--scene/2d/sprite.h3
-rw-r--r--scene/2d/tile_map.cpp39
-rw-r--r--scene/2d/tile_map.h10
-rw-r--r--scene/3d/area.cpp10
-rw-r--r--scene/3d/audio_stream_player_3d.cpp69
-rw-r--r--scene/3d/audio_stream_player_3d.h6
-rw-r--r--scene/3d/baked_lightmap.cpp4
-rw-r--r--scene/3d/camera.cpp281
-rw-r--r--scene/3d/camera.h63
-rw-r--r--scene/3d/collision_object.cpp4
-rw-r--r--scene/3d/collision_object.h1
-rw-r--r--scene/3d/collision_shape.h1
-rw-r--r--scene/3d/cpu_particles.cpp1444
-rw-r--r--scene/3d/cpu_particles.h287
-rw-r--r--scene/3d/gi_probe.cpp1
-rw-r--r--scene/3d/light.cpp1
-rw-r--r--scene/3d/mesh_instance.cpp5
-rw-r--r--scene/3d/mesh_instance.h1
-rw-r--r--scene/3d/navigation.cpp45
-rw-r--r--scene/3d/navigation_mesh.cpp8
-rw-r--r--scene/3d/particles.cpp1222
-rw-r--r--scene/3d/particles.h272
-rw-r--r--scene/3d/physics_body.cpp459
-rw-r--r--scene/3d/physics_body.h40
-rw-r--r--scene/3d/physics_joint.cpp23
-rw-r--r--scene/3d/ray_cast.cpp34
-rw-r--r--scene/3d/ray_cast.h10
-rw-r--r--scene/3d/reflection_probe.cpp1
-rw-r--r--scene/3d/remote_transform.cpp6
-rw-r--r--scene/3d/skeleton.cpp149
-rw-r--r--scene/3d/skeleton.h19
-rw-r--r--scene/3d/soft_body.cpp798
-rw-r--r--scene/3d/soft_body.h199
-rw-r--r--scene/3d/spatial.cpp59
-rw-r--r--scene/3d/spatial.h6
-rw-r--r--scene/3d/spatial_velocity_tracker.cpp6
-rw-r--r--scene/3d/spring_arm.cpp172
-rw-r--r--scene/3d/spring_arm.h71
-rw-r--r--scene/3d/vehicle_body.cpp40
-rw-r--r--scene/3d/vehicle_body.h2
-rw-r--r--scene/3d/visual_instance.cpp16
-rw-r--r--scene/3d/visual_instance.h3
-rw-r--r--scene/3d/voxel_light_baker.cpp154
-rw-r--r--scene/animation/animation_blend_space_1d.cpp104
-rw-r--r--scene/animation/animation_blend_space_1d.h47
-rw-r--r--scene/animation/animation_blend_space_2d.cpp113
-rw-r--r--scene/animation/animation_blend_space_2d.h45
-rw-r--r--scene/animation/animation_blend_tree.cpp612
-rw-r--r--scene/animation/animation_blend_tree.h162
-rw-r--r--scene/animation/animation_cache.cpp12
-rw-r--r--scene/animation/animation_node_state_machine.cpp873
-rw-r--r--scene/animation/animation_node_state_machine.h139
-rw-r--r--scene/animation/animation_player.cpp58
-rw-r--r--scene/animation/animation_player.h1
-rw-r--r--scene/animation/animation_tree.cpp473
-rw-r--r--scene/animation/animation_tree.h102
-rw-r--r--scene/animation/animation_tree_player.cpp14
-rw-r--r--scene/animation/root_motion_view.cpp51
-rw-r--r--scene/animation/root_motion_view.h34
-rw-r--r--scene/animation/skeleton_ik.cpp561
-rw-r--r--scene/animation/skeleton_ik.h216
-rw-r--r--scene/animation/tween.cpp128
-rw-r--r--scene/animation/tween.h9
-rw-r--r--scene/audio/audio_player.cpp46
-rw-r--r--scene/audio/audio_player.h5
-rw-r--r--scene/gui/base_button.cpp2
-rw-r--r--scene/gui/button.cpp3
-rw-r--r--scene/gui/color_picker.cpp30
-rw-r--r--scene/gui/color_picker.h6
-rw-r--r--scene/gui/control.cpp239
-rw-r--r--scene/gui/control.h26
-rw-r--r--scene/gui/file_dialog.cpp19
-rw-r--r--scene/gui/file_dialog.h1
-rw-r--r--scene/gui/gradient_edit.cpp5
-rw-r--r--scene/gui/graph_edit.cpp75
-rw-r--r--scene/gui/graph_edit.h8
-rw-r--r--scene/gui/item_list.cpp58
-rw-r--r--scene/gui/label.cpp2
-rw-r--r--scene/gui/line_edit.cpp113
-rw-r--r--scene/gui/line_edit.h18
-rw-r--r--scene/gui/link_button.cpp2
-rw-r--r--scene/gui/menu_button.h3
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/popup_menu.cpp154
-rw-r--r--scene/gui/popup_menu.h9
-rw-r--r--scene/gui/range.cpp4
-rw-r--r--scene/gui/reference_rect.cpp18
-rw-r--r--scene/gui/reference_rect.h5
-rw-r--r--scene/gui/rich_text_label.cpp74
-rw-r--r--scene/gui/rich_text_label.h5
-rw-r--r--scene/gui/scroll_bar.cpp6
-rw-r--r--scene/gui/slider.cpp25
-rw-r--r--scene/gui/slider.h4
-rw-r--r--scene/gui/tab_container.cpp4
-rw-r--r--scene/gui/tab_container.h6
-rw-r--r--scene/gui/tabs.cpp43
-rw-r--r--scene/gui/tabs.h5
-rw-r--r--scene/gui/text_edit.cpp285
-rw-r--r--scene/gui/text_edit.h18
-rw-r--r--scene/gui/texture_progress.cpp31
-rw-r--r--scene/gui/texture_progress.h5
-rw-r--r--scene/gui/tree.cpp135
-rw-r--r--scene/main/canvas_layer.cpp4
-rw-r--r--scene/main/http_request.cpp20
-rw-r--r--scene/main/node.cpp50
-rw-r--r--scene/main/node.h9
-rw-r--r--scene/main/scene_tree.cpp53
-rw-r--r--scene/main/scene_tree.h3
-rw-r--r--scene/main/viewport.cpp126
-rw-r--r--scene/main/viewport.h9
-rw-r--r--scene/register_scene_types.cpp99
-rw-r--r--scene/resources/animation.cpp107
-rw-r--r--scene/resources/audio_stream_sample.cpp74
-rw-r--r--scene/resources/audio_stream_sample.h2
-rw-r--r--scene/resources/bit_mask.cpp232
-rw-r--r--scene/resources/bit_mask.h2
-rw-r--r--scene/resources/color_ramp.cpp20
-rw-r--r--scene/resources/color_ramp.h6
-rw-r--r--scene/resources/concave_polygon_shape.cpp4
-rw-r--r--scene/resources/convex_polygon_shape.cpp4
-rw-r--r--scene/resources/curve.cpp82
-rw-r--r--scene/resources/curve.h2
-rw-r--r--scene/resources/cylinder_shape.cpp116
-rw-r--r--scene/resources/cylinder_shape.h57
-rw-r--r--scene/resources/default_theme/arrow_down.pngbin184 -> 109 bytes
-rw-r--r--scene/resources/default_theme/arrow_right.pngbin183 -> 103 bytes
-rw-r--r--scene/resources/default_theme/background.pngbin1235 -> 854 bytes
-rw-r--r--scene/resources/default_theme/base_green.pngbin335 -> 86 bytes
-rw-r--r--scene/resources/default_theme/button_disabled.pngbin486 -> 256 bytes
-rw-r--r--scene/resources/default_theme/button_focus.pngbin418 -> 203 bytes
-rw-r--r--scene/resources/default_theme/button_hover.pngbin606 -> 344 bytes
-rw-r--r--scene/resources/default_theme/button_normal.pngbin598 -> 338 bytes
-rw-r--r--scene/resources/default_theme/checked.pngbin627 -> 363 bytes
-rw-r--r--scene/resources/default_theme/checker_bg.pngbin295 -> 77 bytes
-rw-r--r--scene/resources/default_theme/close.pngbin230 -> 155 bytes
-rw-r--r--scene/resources/default_theme/close_hl.pngbin230 -> 155 bytes
-rw-r--r--scene/resources/default_theme/color_picker_sample.pngbin194 -> 117 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp14
-rw-r--r--scene/resources/default_theme/dosfont.pngbin963 -> 683 bytes
-rw-r--r--scene/resources/default_theme/dropdown.pngbin369 -> 133 bytes
-rw-r--r--scene/resources/default_theme/error_icon.pngbin362 -> 111 bytes
-rw-r--r--scene/resources/default_theme/focus.pngbin411 -> 200 bytes
-rw-r--r--scene/resources/default_theme/frame_focus.pngbin448 -> 200 bytes
-rw-r--r--scene/resources/default_theme/full_panel_bg.pngbin430 -> 207 bytes
-rw-r--r--scene/resources/default_theme/graph_node_breakpoint.pngbin277 -> 140 bytes
-rw-r--r--scene/resources/default_theme/graph_node_close.pngbin222 -> 152 bytes
-rw-r--r--scene/resources/default_theme/graph_node_comment.pngbin506 -> 382 bytes
-rw-r--r--scene/resources/default_theme/graph_node_comment_focus.pngbin482 -> 373 bytes
-rw-r--r--scene/resources/default_theme/graph_node_default.pngbin420 -> 205 bytes
-rw-r--r--scene/resources/default_theme/graph_node_default_focus.pngbin452 -> 195 bytes
-rw-r--r--scene/resources/default_theme/graph_node_position.pngbin278 -> 140 bytes
-rw-r--r--scene/resources/default_theme/graph_node_selected.pngbin933 -> 836 bytes
-rw-r--r--scene/resources/default_theme/graph_port.pngbin273 -> 171 bytes
-rw-r--r--scene/resources/default_theme/hseparator.pngbin323 -> 112 bytes
-rw-r--r--scene/resources/default_theme/hslider_bg.pngbin526 -> 263 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber.pngbin591 -> 300 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber_disabled.pngbin386 -> 288 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber_hl.pngbin734 -> 450 bytes
-rw-r--r--scene/resources/default_theme/hslider_tick.pngbin364 -> 149 bytes
-rw-r--r--scene/resources/default_theme/hsplit_bg.pngbin334 -> 85 bytes
-rw-r--r--scene/resources/default_theme/hsplitter.pngbin359 -> 97 bytes
-rw-r--r--scene/resources/default_theme/icon_add.pngbin129 -> 86 bytes
-rw-r--r--scene/resources/default_theme/icon_close.pngbin230 -> 155 bytes
-rw-r--r--scene/resources/default_theme/icon_color_pick.pngbin416 -> 227 bytes
-rw-r--r--scene/resources/default_theme/icon_folder.pngbin170 -> 103 bytes
-rw-r--r--scene/resources/default_theme/icon_parent_folder.pngbin329 -> 161 bytes
-rw-r--r--scene/resources/default_theme/icon_play.pngbin237 -> 122 bytes
-rw-r--r--scene/resources/default_theme/icon_reload.pngbin420 -> 234 bytes
-rw-r--r--scene/resources/default_theme/icon_snap_grid.pngbin325 -> 226 bytes
-rw-r--r--scene/resources/default_theme/icon_stop.pngbin312 -> 87 bytes
-rw-r--r--scene/resources/default_theme/icon_zoom_less.pngbin112 -> 76 bytes
-rw-r--r--scene/resources/default_theme/icon_zoom_more.pngbin129 -> 85 bytes
-rw-r--r--scene/resources/default_theme/icon_zoom_reset.pngbin186 -> 108 bytes
-rw-r--r--scene/resources/default_theme/line_edit.pngbin424 -> 176 bytes
-rw-r--r--scene/resources/default_theme/line_edit_clear.pngbin0 -> 158 bytes
-rw-r--r--scene/resources/default_theme/line_edit_disabled.pngbin406 -> 135 bytes
-rw-r--r--scene/resources/default_theme/line_edit_focus.pngbin660 -> 365 bytes
-rw-r--r--scene/resources/default_theme/logo.pngbin8809 -> 6676 bytes
-rwxr-xr-xscene/resources/default_theme/make_header.py26
-rw-r--r--scene/resources/default_theme/mini_checkerboard.pngbin166 -> 80 bytes
-rw-r--r--scene/resources/default_theme/option_arrow.pngbin227 -> 119 bytes
-rw-r--r--scene/resources/default_theme/option_button_disabled.pngbin901 -> 656 bytes
-rw-r--r--scene/resources/default_theme/option_button_focus.pngbin679 -> 416 bytes
-rw-r--r--scene/resources/default_theme/option_button_hover.pngbin924 -> 667 bytes
-rw-r--r--scene/resources/default_theme/option_button_normal.pngbin922 -> 669 bytes
-rw-r--r--scene/resources/default_theme/option_button_pressed.pngbin931 -> 677 bytes
-rw-r--r--scene/resources/default_theme/panel_bg.pngbin334 -> 85 bytes
-rw-r--r--scene/resources/default_theme/popup_bg.pngbin672 -> 410 bytes
-rw-r--r--scene/resources/default_theme/popup_bg_disabled.pngbin582 -> 362 bytes
-rw-r--r--scene/resources/default_theme/popup_checked.pngbin238 -> 143 bytes
-rw-r--r--scene/resources/default_theme/popup_hover.pngbin404 -> 145 bytes
-rw-r--r--scene/resources/default_theme/popup_unchecked.pngbin310 -> 98 bytes
-rw-r--r--scene/resources/default_theme/popup_window.pngbin1234 -> 903 bytes
-rw-r--r--scene/resources/default_theme/progress_bar.pngbin460 -> 194 bytes
-rw-r--r--scene/resources/default_theme/progress_fill.pngbin402 -> 112 bytes
-rw-r--r--scene/resources/default_theme/radio_checked.pngbin477 -> 257 bytes
-rw-r--r--scene/resources/default_theme/radio_unchecked.pngbin422 -> 207 bytes
-rw-r--r--scene/resources/default_theme/reference_border.pngbin348 -> 132 bytes
-rw-r--r--scene/resources/default_theme/scroll_bg.pngbin510 -> 252 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_down.pngbin418 -> 170 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_down_hl.pngbin418 -> 170 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_left.pngbin444 -> 196 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_left_hl.pngbin461 -> 200 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_right.pngbin446 -> 198 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_right_hl.pngbin464 -> 210 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_up.pngbin421 -> 173 bytes
-rw-r--r--scene/resources/default_theme/scroll_button_up_hl.pngbin421 -> 173 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber.pngbin523 -> 264 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber_hl.pngbin536 -> 278 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber_pressed.pngbin233 -> 104 bytes
-rw-r--r--scene/resources/default_theme/selection.pngbin406 -> 195 bytes
-rw-r--r--scene/resources/default_theme/selection_oof.pngbin411 -> 196 bytes
-rw-r--r--scene/resources/default_theme/spinbox_updown.pngbin280 -> 146 bytes
-rw-r--r--scene/resources/default_theme/submenu.pngbin175 -> 103 bytes
-rw-r--r--scene/resources/default_theme/tab.pngbin300 -> 82 bytes
-rw-r--r--scene/resources/default_theme/tab_behind.pngbin553 -> 282 bytes
-rw-r--r--scene/resources/default_theme/tab_close.pngbin325 -> 158 bytes
-rw-r--r--scene/resources/default_theme/tab_container_bg.pngbin598 -> 338 bytes
-rw-r--r--scene/resources/default_theme/tab_current.pngbin627 -> 347 bytes
-rw-r--r--scene/resources/default_theme/tab_menu.pngbin186 -> 111 bytes
-rw-r--r--scene/resources/default_theme/tab_menu_hl.pngbin186 -> 111 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h236
-rw-r--r--scene/resources/default_theme/toggle_off.pngbin1355 -> 1077 bytes
-rw-r--r--scene/resources/default_theme/toggle_on.pngbin1318 -> 1034 bytes
-rw-r--r--scene/resources/default_theme/tool_button_pressed.pngbin1230 -> 864 bytes
-rw-r--r--scene/resources/default_theme/tooltip_bg.pngbin424 -> 198 bytes
-rw-r--r--scene/resources/default_theme/tree_bg.pngbin424 -> 176 bytes
-rw-r--r--scene/resources/default_theme/tree_bg_disabled.pngbin406 -> 135 bytes
-rw-r--r--scene/resources/default_theme/tree_bg_focus.pngbin1039 -> 696 bytes
-rw-r--r--scene/resources/default_theme/tree_cursor.pngbin743 -> 434 bytes
-rw-r--r--scene/resources/default_theme/tree_cursor_unfocus.pngbin655 -> 369 bytes
-rw-r--r--scene/resources/default_theme/tree_title.pngbin335 -> 86 bytes
-rw-r--r--scene/resources/default_theme/tree_title_pressed.pngbin335 -> 86 bytes
-rw-r--r--scene/resources/default_theme/unchecked.pngbin477 -> 222 bytes
-rw-r--r--scene/resources/default_theme/updown.pngbin241 -> 144 bytes
-rw-r--r--scene/resources/default_theme/vseparator.pngbin323 -> 108 bytes
-rw-r--r--scene/resources/default_theme/vslider_bg.pngbin532 -> 276 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber.pngbin394 -> 245 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber_disabled.pngbin335 -> 237 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber_hl.pngbin439 -> 261 bytes
-rw-r--r--scene/resources/default_theme/vslider_tick.pngbin360 -> 145 bytes
-rw-r--r--scene/resources/default_theme/vsplit_bg.pngbin334 -> 85 bytes
-rw-r--r--scene/resources/default_theme/vsplitter.pngbin351 -> 95 bytes
-rw-r--r--scene/resources/default_theme/window_resizer.pngbin181 -> 87 bytes
-rw-r--r--scene/resources/dynamic_font.cpp34
-rw-r--r--scene/resources/dynamic_font_stb.cpp5
-rw-r--r--scene/resources/environment.cpp37
-rw-r--r--scene/resources/environment.h4
-rw-r--r--scene/resources/font.cpp4
-rw-r--r--scene/resources/material.cpp118
-rw-r--r--scene/resources/material.h25
-rw-r--r--scene/resources/mesh.cpp127
-rw-r--r--scene/resources/mesh.h7
-rw-r--r--scene/resources/mesh_data_tool.cpp30
-rw-r--r--scene/resources/mesh_library.cpp2
-rw-r--r--scene/resources/packed_scene.cpp63
-rw-r--r--scene/resources/particles_material.cpp1259
-rw-r--r--scene/resources/particles_material.h302
-rw-r--r--scene/resources/physics_material.cpp77
-rw-r--r--scene/resources/physics_material.h75
-rw-r--r--scene/resources/polygon_path_finder.cpp80
-rw-r--r--scene/resources/scene_format_text.cpp4
-rw-r--r--scene/resources/shader.cpp18
-rw-r--r--scene/resources/shader.h3
-rw-r--r--scene/resources/shader_graph.cpp2596
-rw-r--r--scene/resources/shader_graph.h446
-rw-r--r--scene/resources/shape.cpp23
-rw-r--r--scene/resources/shape.h6
-rw-r--r--scene/resources/sky_box.cpp16
-rw-r--r--scene/resources/style_box.cpp36
-rw-r--r--scene/resources/style_box.h10
-rw-r--r--scene/resources/surface_tool.cpp47
-rw-r--r--scene/resources/text_file.cpp77
-rw-r--r--scene/resources/text_file.h55
-rw-r--r--scene/resources/texture.cpp737
-rw-r--r--scene/resources/texture.h172
-rw-r--r--scene/resources/theme.h12
-rw-r--r--scene/resources/tile_set.cpp45
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/visual_shader.cpp1583
-rw-r--r--scene/resources/visual_shader.h314
-rw-r--r--scene/resources/visual_shader_nodes.cpp1926
-rw-r--r--scene/resources/visual_shader_nodes.h891
-rw-r--r--scene/scene_string_names.cpp4
-rw-r--r--scene/scene_string_names.h4
321 files changed, 19283 insertions, 7450 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 54194ff543..85e7f8df92 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -59,15 +59,36 @@ bool AnimatedSprite::_edit_use_pivot() const {
}
Rect2 AnimatedSprite::_edit_get_rect() const {
+ return _get_rect();
+}
+
+bool AnimatedSprite::_edit_use_rect() const {
if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
- return Node2D::_edit_get_rect();
+ return false;
+ }
+ Ref<Texture> t;
+ if (animation)
+ t = frames->get_frame(animation, frame);
+ if (t.is_null())
+ return false;
+
+ return true;
+}
+
+Rect2 AnimatedSprite::get_anchorable_rect() const {
+ return _get_rect();
+}
+
+Rect2 AnimatedSprite::_get_rect() const {
+ if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return Rect2();
}
Ref<Texture> t;
if (animation)
t = frames->get_frame(animation, frame);
if (t.is_null())
- return Node2D::_edit_get_rect();
+ return Rect2();
Size2 s = t->get_size();
Point2 ofs = offset;
@@ -80,10 +101,6 @@ Rect2 AnimatedSprite::_edit_get_rect() const {
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) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
@@ -175,6 +192,16 @@ void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
}
}
+Vector<String> SpriteFrames::get_animation_names() const {
+
+ Vector<String> names;
+ for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+ names.push_back(E->key());
+ }
+ names.sort();
+ return names;
+}
+
void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
ERR_FAIL_COND(p_fps < 0);
@@ -208,7 +235,7 @@ void SpriteFrames::_set_frames(const Array &p_frames) {
E->get().frames.resize(p_frames.size());
for (int i = 0; i < E->get().frames.size(); i++)
- E->get().frames[i] = p_frames[i];
+ E->get().frames.write[i] = p_frames[i];
}
Array SpriteFrames::_get_frames() const {
@@ -266,6 +293,8 @@ void SpriteFrames::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
+ ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
+
ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index be5b1ef6d6..cc49465403 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -72,6 +72,7 @@ public:
void rename_animation(const StringName &p_prev, const StringName &p_next);
void get_animation_list(List<StringName> *r_animations) const;
+ Vector<String> get_animation_names() const;
void set_animation_speed(const StringName &p_anim, float p_fps);
float get_animation_speed(const StringName &p_anim) const;
@@ -112,7 +113,7 @@ public:
ERR_FAIL_COND(p_idx < 0);
if (p_idx >= E->get().frames.size())
return;
- E->get().frames[p_idx] = p_frame;
+ E->get().frames.write[p_idx] = p_frame;
}
void remove_frame(const StringName &p_anim, int p_idx);
void clear(const StringName &p_anim);
@@ -145,6 +146,7 @@ class AnimatedSprite : public Node2D {
void _reset_timeout();
void _set_playing(bool p_playing);
bool _is_playing() const;
+ Rect2 _get_rect() const;
protected:
static void _bind_methods();
@@ -161,6 +163,8 @@ public:
virtual Rect2 _edit_get_rect() const;
virtual bool _edit_use_rect() const;
+ virtual Rect2 get_anchorable_rect() const;
+
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 54541293fd..559e041dbf 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -36,11 +36,8 @@
void AudioStreamPlayer2D::_mix_audio() {
- if (!stream_playback.is_valid()) {
- return;
- }
-
- if (!active) {
+ if (!stream_playback.is_valid() || !active ||
+ (stream_paused && !stream_paused_fade_out)) {
return;
}
@@ -53,7 +50,11 @@ void AudioStreamPlayer2D::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
- //mix
+ if (stream_paused_fade_out) {
+ // Short fadeout ramp
+ buffer_size = MIN(buffer_size, 128);
+ }
+
stream_playback->mix(buffer, pitch_scale, buffer_size);
//write all outputs
@@ -83,8 +84,10 @@ void AudioStreamPlayer2D::_mix_audio() {
}
//mix!
- AudioFrame vol_inc = (current.vol - prev_outputs[i].vol) / float(buffer_size);
- AudioFrame vol = current.vol;
+ AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol;
+ AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol;
+ AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
+ AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol;
int cc = AudioServer::get_singleton()->get_channel_count();
@@ -125,6 +128,8 @@ void AudioStreamPlayer2D::_mix_audio() {
}
output_ready = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
}
void AudioStreamPlayer2D::_notification(int p_what) {
@@ -142,6 +147,17 @@ void AudioStreamPlayer2D::_notification(int p_what) {
AudioServer::get_singleton()->remove_callback(_mix_audios, this);
}
+ if (p_what == NOTIFICATION_PAUSED) {
+ if (!can_process()) {
+ // Node can't process so we start fading out to silence
+ set_stream_paused(true);
+ }
+ }
+
+ if (p_what == NOTIFICATION_UNPAUSED) {
+ set_stream_paused(false);
+ }
+
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
@@ -242,7 +258,6 @@ void AudioStreamPlayer2D::_notification(int p_what) {
void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
- ERR_FAIL_COND(!p_stream.is_valid());
AudioServer::get_singleton()->lock();
mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
@@ -254,14 +269,15 @@ void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
setseek = -1;
}
- stream = p_stream;
- stream_playback = p_stream->instance_playback();
+ if (p_stream.is_valid()) {
+ stream = p_stream;
+ stream_playback = p_stream->instance_playback();
+ }
AudioServer::get_singleton()->unlock();
- if (stream_playback.is_null()) {
+ if (p_stream.is_valid() && stream_playback.is_null()) {
stream.unref();
- ERR_FAIL_COND(stream_playback.is_null());
}
}
@@ -280,6 +296,7 @@ float AudioStreamPlayer2D::get_volume_db() const {
}
void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {
+ ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
}
float AudioStreamPlayer2D::get_pitch_scale() const {
@@ -288,6 +305,11 @@ float AudioStreamPlayer2D::get_pitch_scale() const {
void AudioStreamPlayer2D::play(float p_from_pos) {
+ if (!is_playing()) {
+ // Reset the prev_output_count if the stream is stopped
+ prev_output_count = 0;
+ }
+
if (stream_playback.is_valid()) {
setplay = p_from_pos;
output_ready = false;
@@ -418,6 +440,20 @@ uint32_t AudioStreamPlayer2D::get_area_mask() const {
return area_mask;
}
+void AudioStreamPlayer2D::set_stream_paused(bool p_pause) {
+
+ if (p_pause != stream_paused) {
+ stream_paused = p_pause;
+ stream_paused_fade_in = p_pause ? false : true;
+ stream_paused_fade_out = p_pause ? true : false;
+ }
+}
+
+bool AudioStreamPlayer2D::get_stream_paused() const {
+
+ return stream_paused;
+}
+
void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream);
@@ -454,6 +490,9 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer2D::set_area_mask);
ClassDB::bind_method(D_METHOD("get_area_mask"), &AudioStreamPlayer2D::get_area_mask);
+ ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer2D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -461,6 +500,7 @@ void AudioStreamPlayer2D::_bind_methods() {
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::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
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");
@@ -483,6 +523,9 @@ AudioStreamPlayer2D::AudioStreamPlayer2D() {
setplay = -1;
output_ready = false;
area_mask = 1;
+ stream_paused = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
}
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index 9ae8e3a518..e68e6eeca5 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -72,6 +72,9 @@ private:
float volume_db;
float pitch_scale;
bool autoplay;
+ bool stream_paused;
+ bool stream_paused_fade_in;
+ bool stream_paused_fade_out;
StringName bus;
void _mix_audio();
@@ -123,6 +126,9 @@ public:
void set_area_mask(uint32_t p_mask);
uint32_t get_area_mask() const;
+ void set_stream_paused(bool p_pause);
+ bool get_stream_paused() const;
+
AudioStreamPlayer2D();
~AudioStreamPlayer2D();
};
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp
index caa1adebdb..e06c30ec6b 100644
--- a/scene/2d/back_buffer_copy.cpp
+++ b/scene/2d/back_buffer_copy.cpp
@@ -59,6 +59,11 @@ bool BackBufferCopy::_edit_use_rect() const {
return true;
}
+Rect2 BackBufferCopy::get_anchorable_rect() const {
+
+ return rect;
+}
+
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 752d56de2b..b1ee12544b 100644
--- a/scene/2d/back_buffer_copy.h
+++ b/scene/2d/back_buffer_copy.h
@@ -58,6 +58,7 @@ public:
void set_rect(const Rect2 &p_rect);
Rect2 get_rect() const;
+ Rect2 get_anchorable_rect() const;
void set_copy_mode(CopyMode p_mode);
CopyMode get_copy_mode() const;
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index f1c09594da..7f7e3542ed 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -321,11 +321,6 @@ void CanvasItem::hide() {
_change_notify("visible");
}
-Size2 CanvasItem::_edit_get_minimum_size() const {
-
- return Size2(-1, -1); //no limit
-}
-
void CanvasItem::_update_callback() {
if (!is_inside_tree()) {
@@ -354,23 +349,12 @@ void CanvasItem::_update_callback() {
Transform2D CanvasItem::get_global_transform_with_canvas() const {
- const CanvasItem *ci = this;
- Transform2D xform;
- const CanvasItem *last_valid = NULL;
-
- while (ci) {
-
- last_valid = ci;
- xform = ci->get_transform() * xform;
- ci = ci->get_parent_item();
- }
-
- if (last_valid->canvas_layer)
- return last_valid->canvas_layer->get_transform() * xform;
+ if (canvas_layer)
+ return canvas_layer->get_transform() * get_global_transform();
else if (is_inside_tree())
- return get_viewport()->get_canvas_transform() * xform;
-
- return xform;
+ return get_viewport()->get_canvas_transform() * get_global_transform();
+ else
+ return get_global_transform();
}
Transform2D CanvasItem::get_global_transform() const {
@@ -416,6 +400,9 @@ void CanvasItem::_enter_canvas() {
if (canvas_layer) {
break;
}
+ if (Object::cast_to<Viewport>(n)) {
+ break;
+ }
n = n->get_parent();
}
@@ -994,7 +981,6 @@ void CanvasItem::_bind_methods() {
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);
- ClassDB::bind_method(D_METHOD("_edit_get_item_and_children_rect"), &CanvasItem::_edit_get_item_and_children_rect);
ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
@@ -1175,21 +1161,6 @@ int CanvasItem::get_canvas_layer() const {
return 0;
}
-Rect2 CanvasItem::_edit_get_item_and_children_rect() const {
-
- Rect2 rect = _edit_get_rect();
-
- for (int i = 0; i < get_child_count(); i++) {
- CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
- if (c) {
- Rect2 sir = c->get_transform().xform(c->_edit_get_item_and_children_rect());
- rect = rect.merge(sir);
- }
- }
-
- return rect;
-}
-
CanvasItem::CanvasItem() :
xform_change(this) {
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index 10d5082dfc..1e6a251c9c 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -222,6 +222,9 @@ public:
/* EDITOR */
+ // Select the node
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
// Save and restore a CanvasItem state
virtual void _edit_set_state(const Dictionary &p_state){};
virtual Dictionary _edit_get_state() const { return Dictionary(); };
@@ -234,36 +237,21 @@ public:
virtual void _edit_set_scale(const Size2 &p_scale) = 0;
virtual Size2 _edit_get_scale() const = 0;
+ // Used to rotate the node
+ 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; };
+
// Used to resize/move the node
+ virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
virtual void _edit_set_rect(const Rect2 &p_rect){};
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 Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
// Used to set a pivot
+ virtual bool _edit_use_pivot() const { return false; };
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 Size2 _edit_get_minimum_size() const;
+ virtual Point2 _edit_get_pivot() const { return Point2(); };
/* VISIBILITY */
@@ -358,6 +346,9 @@ public:
void set_notify_transform(bool p_enable);
bool is_transform_notification_enabled() const;
+ // Used by control nodes to retreive the parent's anchorable area
+ virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
+
int get_canvas_layer() const;
CanvasItem();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index d05c818ae1..7ade74e8a6 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -38,10 +38,14 @@ void CollisionObject2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
+ Transform2D global_transform = get_global_transform();
+
if (area)
- Physics2DServer::get_singleton()->area_set_transform(rid, get_global_transform());
+ Physics2DServer::get_singleton()->area_set_transform(rid, global_transform);
else
- Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, get_global_transform());
+ Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, global_transform);
+
+ last_transform = global_transform;
RID space = get_world_2d()->get_space();
if (area) {
@@ -60,10 +64,18 @@ void CollisionObject2D::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
+ Transform2D global_transform = get_global_transform();
+
+ if (only_update_transform_changes && global_transform == last_transform) {
+ return;
+ }
+
if (area)
- Physics2DServer::get_singleton()->area_set_transform(rid, get_global_transform());
+ Physics2DServer::get_singleton()->area_set_transform(rid, global_transform);
else
- Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, get_global_transform());
+ Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, global_transform);
+
+ last_transform = global_transform;
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -247,7 +259,7 @@ void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().shapes.size(); i++) {
if (E->get().shapes[i].index > index_to_remove) {
- E->get().shapes[i].index -= 1;
+ E->get().shapes.write[i].index -= 1;
}
}
}
@@ -318,6 +330,10 @@ void CollisionObject2D::_mouse_exit() {
emit_signal(SceneStringNames::get_singleton()->mouse_exited);
}
+void CollisionObject2D::set_only_update_transform_changes(bool p_enable) {
+ only_update_transform_changes = p_enable;
+}
+
void CollisionObject2D::_update_pickable() {
if (!is_inside_tree())
return;
@@ -368,7 +384,7 @@ void CollisionObject2D::_bind_methods() {
BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "viewport"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
- ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
+ ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
@@ -384,6 +400,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
pickable = true;
set_notify_transform(true);
total_subshapes = 0;
+ only_update_transform_changes = false;
if (p_area) {
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 6da63d1a0b..29a00bd9f9 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -65,6 +65,8 @@ class CollisionObject2D : public Node2D {
int total_subshapes;
Map<uint32_t, ShapeData> shapes;
+ Transform2D last_transform;
+ bool only_update_transform_changes; //this is used for sync physics in KinematicBody
protected:
CollisionObject2D(RID p_rid, bool p_area);
@@ -78,6 +80,8 @@ protected:
void _mouse_enter();
void _mouse_exit();
+ void set_only_update_transform_changes(bool p_enable);
+
public:
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 9d2a83fda7..9f19f56e75 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -102,11 +102,11 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
TriangulatorPoly &tp = I->get();
- decomp[idx].resize(tp.GetNumPoints());
+ decomp.write[idx].resize(tp.GetNumPoints());
for (int i = 0; i < tp.GetNumPoints(); i++) {
- decomp[idx][i] = tp.GetPoint(i);
+ decomp.write[idx].write[i] = tp.GetPoint(i);
}
idx++;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 83ef4df8f4..ff5f7062c4 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -119,7 +119,7 @@ void CollisionShape2D::_notification(int p_what) {
Color draw_col = get_tree()->get_debug_collisions_color();
if (disabled) {
- float g = draw_col.gray();
+ float g = draw_col.get_v();
draw_col.r = g;
draw_col.g = g;
draw_col.b = g;
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
new file mode 100644
index 0000000000..a8e0f0d07f
--- /dev/null
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -0,0 +1,1402 @@
+/*************************************************************************/
+/* cpu_particles_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 "cpu_particles_2d.h"
+
+//#include "scene/resources/particles_material.h"
+#include "servers/visual_server.h"
+
+void CPUParticles2D::set_emitting(bool p_emitting) {
+
+ emitting = p_emitting;
+ if (!is_processing_internal()) {
+ set_process_internal(true);
+ if (is_inside_tree()) {
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ }
+ }
+}
+
+void CPUParticles2D::set_amount(int p_amount) {
+
+ ERR_FAIL_COND(p_amount < 1);
+
+ particles.resize(p_amount);
+ {
+ PoolVector<Particle>::Write w = particles.write();
+
+ for (int i = 0; i < p_amount; i++) {
+ w[i].active = false;
+ }
+ }
+
+ particle_data.resize((8 + 4 + 1) * p_amount);
+ VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_2D, VS::MULTIMESH_COLOR_8BIT, VS::MULTIMESH_CUSTOM_DATA_FLOAT);
+
+ particle_order.resize(p_amount);
+}
+void CPUParticles2D::set_lifetime(float p_lifetime) {
+
+ ERR_FAIL_COND(p_lifetime <= 0);
+ lifetime = p_lifetime;
+}
+
+void CPUParticles2D::set_one_shot(bool p_one_shot) {
+
+ one_shot = p_one_shot;
+}
+
+void CPUParticles2D::set_pre_process_time(float p_time) {
+
+ pre_process_time = p_time;
+}
+void CPUParticles2D::set_explosiveness_ratio(float p_ratio) {
+
+ explosiveness_ratio = p_ratio;
+}
+void CPUParticles2D::set_randomness_ratio(float p_ratio) {
+
+ randomness_ratio = p_ratio;
+}
+void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
+
+ local_coords = p_enable;
+}
+void CPUParticles2D::set_speed_scale(float p_scale) {
+
+ speed_scale = p_scale;
+}
+
+bool CPUParticles2D::is_emitting() const {
+
+ return emitting;
+}
+int CPUParticles2D::get_amount() const {
+
+ return particles.size();
+}
+float CPUParticles2D::get_lifetime() const {
+
+ return lifetime;
+}
+bool CPUParticles2D::get_one_shot() const {
+
+ return one_shot;
+}
+
+float CPUParticles2D::get_pre_process_time() const {
+
+ return pre_process_time;
+}
+float CPUParticles2D::get_explosiveness_ratio() const {
+
+ return explosiveness_ratio;
+}
+float CPUParticles2D::get_randomness_ratio() const {
+
+ return randomness_ratio;
+}
+
+bool CPUParticles2D::get_use_local_coordinates() const {
+
+ return local_coords;
+}
+
+float CPUParticles2D::get_speed_scale() const {
+
+ return speed_scale;
+}
+
+void CPUParticles2D::set_draw_order(DrawOrder p_order) {
+
+ draw_order = p_order;
+}
+
+CPUParticles2D::DrawOrder CPUParticles2D::get_draw_order() const {
+
+ return draw_order;
+}
+
+void CPUParticles2D::_update_mesh_texture() {
+
+ Size2 tex_size;
+ if (texture.is_valid()) {
+ tex_size = texture->get_size();
+ } else {
+ tex_size = Size2(1, 1);
+ }
+ PoolVector<Vector2> vertices;
+ vertices.push_back(-tex_size * 0.5);
+ vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, 0));
+ vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, tex_size.y));
+ vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y));
+ PoolVector<Vector2> uvs;
+ uvs.push_back(Vector2(0, 0));
+ uvs.push_back(Vector2(1, 0));
+ uvs.push_back(Vector2(1, 1));
+ uvs.push_back(Vector2(0, 1));
+ PoolVector<Color> colors;
+ colors.push_back(Color(1, 1, 1, 1));
+ colors.push_back(Color(1, 1, 1, 1));
+ colors.push_back(Color(1, 1, 1, 1));
+ colors.push_back(Color(1, 1, 1, 1));
+ PoolVector<int> indices;
+ indices.push_back(0);
+ indices.push_back(1);
+ indices.push_back(2);
+ indices.push_back(2);
+ indices.push_back(3);
+ indices.push_back(0);
+
+ Array arr;
+ arr.resize(VS::ARRAY_MAX);
+ arr[VS::ARRAY_VERTEX] = vertices;
+ arr[VS::ARRAY_TEX_UV] = uvs;
+ arr[VS::ARRAY_COLOR] = colors;
+ arr[VS::ARRAY_INDEX] = indices;
+
+ VS::get_singleton()->mesh_clear(mesh);
+ VS::get_singleton()->mesh_add_surface_from_arrays(mesh, VS::PRIMITIVE_TRIANGLES, arr);
+}
+
+void CPUParticles2D::set_texture(const Ref<Texture> &p_texture) {
+
+ texture = p_texture;
+ update();
+ _update_mesh_texture();
+}
+
+Ref<Texture> CPUParticles2D::get_texture() const {
+
+ return texture;
+}
+
+void CPUParticles2D::set_normalmap(const Ref<Texture> &p_normalmap) {
+
+ normalmap = p_normalmap;
+ update();
+}
+
+Ref<Texture> CPUParticles2D::get_normalmap() const {
+
+ return normalmap;
+}
+
+void CPUParticles2D::set_fixed_fps(int p_count) {
+ fixed_fps = p_count;
+}
+
+int CPUParticles2D::get_fixed_fps() const {
+ return fixed_fps;
+}
+
+void CPUParticles2D::set_fractional_delta(bool p_enable) {
+ fractional_delta = p_enable;
+}
+
+bool CPUParticles2D::get_fractional_delta() const {
+ return fractional_delta;
+}
+
+String CPUParticles2D::get_configuration_warning() const {
+
+ String warnings;
+
+ return warnings;
+}
+
+void CPUParticles2D::restart() {
+
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+
+ {
+ int pc = particles.size();
+ PoolVector<Particle>::Write w = particles.write();
+
+ for (int i = 0; i < pc; i++) {
+ w[i].active = false;
+ }
+ }
+}
+
+void CPUParticles2D::set_spread(float p_spread) {
+
+ spread = p_spread;
+}
+
+float CPUParticles2D::get_spread() const {
+
+ return spread;
+}
+
+void CPUParticles2D::set_flatness(float p_flatness) {
+
+ flatness = p_flatness;
+}
+float CPUParticles2D::get_flatness() const {
+
+ return flatness;
+}
+
+void CPUParticles2D::set_param(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ parameters[p_param] = p_value;
+}
+float CPUParticles2D::get_param(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return parameters[p_param];
+}
+
+void CPUParticles2D::set_param_randomness(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ randomness[p_param] = p_value;
+}
+float CPUParticles2D::get_param_randomness(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return randomness[p_param];
+}
+
+static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) {
+
+ Ref<Curve> curve = p_curve;
+ if (!curve.is_valid())
+ return;
+
+ curve->ensure_default_setup(p_min, p_max);
+}
+
+void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ curve_parameters[p_param] = p_curve;
+
+ switch (p_param) {
+ case PARAM_INITIAL_LINEAR_VELOCITY: {
+ //do none for this one
+ } break;
+ case PARAM_ANGULAR_VELOCITY: {
+ _adjust_curve_range(p_curve, -360, 360);
+ } break;
+ /*case PARAM_ORBIT_VELOCITY: {
+ _adjust_curve_range(p_curve, -500, 500);
+ } break;*/
+ case PARAM_LINEAR_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_RADIAL_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_TANGENTIAL_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_DAMPING: {
+ _adjust_curve_range(p_curve, 0, 100);
+ } break;
+ case PARAM_ANGLE: {
+ _adjust_curve_range(p_curve, -360, 360);
+ } break;
+ case PARAM_SCALE: {
+
+ } break;
+ case PARAM_HUE_VARIATION: {
+ _adjust_curve_range(p_curve, -1, 1);
+ } break;
+ case PARAM_ANIM_SPEED: {
+ _adjust_curve_range(p_curve, 0, 200);
+ } break;
+ case PARAM_ANIM_OFFSET: {
+ } break;
+ default: {}
+ }
+}
+Ref<Curve> CPUParticles2D::get_param_curve(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>());
+
+ return curve_parameters[p_param];
+}
+
+void CPUParticles2D::set_color(const Color &p_color) {
+
+ color = p_color;
+}
+
+Color CPUParticles2D::get_color() const {
+
+ return color;
+}
+
+void CPUParticles2D::set_color_ramp(const Ref<Gradient> &p_ramp) {
+
+ color_ramp = p_ramp;
+}
+
+Ref<Gradient> CPUParticles2D::get_color_ramp() const {
+
+ return color_ramp;
+}
+
+void CPUParticles2D::set_particle_flag(Flags p_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ flags[p_flag] = p_enable;
+}
+
+bool CPUParticles2D::get_particle_flag(Flags p_flag) const {
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags[p_flag];
+}
+
+void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
+
+ emission_shape = p_shape;
+}
+
+void CPUParticles2D::set_emission_sphere_radius(float p_radius) {
+
+ emission_sphere_radius = p_radius;
+}
+
+void CPUParticles2D::set_emission_rect_extents(Vector2 p_extents) {
+
+ emission_rect_extents = p_extents;
+}
+
+void CPUParticles2D::set_emission_points(const PoolVector<Vector2> &p_points) {
+
+ emission_points = p_points;
+}
+
+void CPUParticles2D::set_emission_normals(const PoolVector<Vector2> &p_normals) {
+
+ emission_normals = p_normals;
+}
+
+void CPUParticles2D::set_emission_colors(const PoolVector<Color> &p_colors) {
+
+ emission_colors = p_colors;
+}
+
+float CPUParticles2D::get_emission_sphere_radius() const {
+
+ return emission_sphere_radius;
+}
+Vector2 CPUParticles2D::get_emission_rect_extents() const {
+
+ return emission_rect_extents;
+}
+PoolVector<Vector2> CPUParticles2D::get_emission_points() const {
+
+ return emission_points;
+}
+PoolVector<Vector2> CPUParticles2D::get_emission_normals() const {
+
+ return emission_normals;
+}
+
+PoolVector<Color> CPUParticles2D::get_emission_colors() const {
+
+ return emission_colors;
+}
+
+CPUParticles2D::EmissionShape CPUParticles2D::get_emission_shape() const {
+ return emission_shape;
+}
+void CPUParticles2D::set_gravity(const Vector2 &p_gravity) {
+
+ gravity = p_gravity;
+}
+
+Vector2 CPUParticles2D::get_gravity() const {
+
+ return gravity;
+}
+
+void CPUParticles2D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "color" && color_ramp.is_valid()) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_CIRCLE) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) {
+ property.usage = 0;
+ }
+
+ if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ property.usage = 0;
+ }
+ /*
+ if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ property.usage = 0;
+ }
+ */
+}
+
+static uint32_t idhash(uint32_t x) {
+
+ x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
+ x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
+ x = (x >> uint32_t(16)) ^ x;
+ return x;
+}
+
+static float rand_from_seed(uint32_t &seed) {
+ int k;
+ int s = int(seed);
+ if (s == 0)
+ s = 305420679;
+ k = s / 127773;
+ s = 16807 * (s - k * 127773) - 2836 * k;
+ if (s < 0)
+ s += 2147483647;
+ seed = uint32_t(s);
+ return float(seed % uint32_t(65536)) / 65535.0;
+}
+
+static float rand_from_seed_m1_p1(uint32_t &seed) {
+ return rand_from_seed(seed) * 2.0 - 1.0;
+}
+
+void CPUParticles2D::_particles_process(float p_delta) {
+
+ p_delta *= speed_scale;
+
+ int pcount = particles.size();
+ PoolVector<Particle>::Write w = particles.write();
+
+ Particle *parray = w.ptr();
+
+ float prev_time = time;
+ time += p_delta;
+ if (time > lifetime) {
+ time = Math::fmod(time, lifetime);
+ cycle++;
+ if (one_shot && cycle > 0) {
+ emitting = false;
+ }
+ }
+
+ Transform2D emission_xform;
+ Transform2D velocity_xform;
+ if (!local_coords) {
+ emission_xform = get_global_transform();
+ velocity_xform = emission_xform;
+ emission_xform[2] = Vector2();
+ }
+
+ for (int i = 0; i < pcount; i++) {
+
+ Particle &p = parray[i];
+
+ if (!emitting && !p.active)
+ continue;
+
+ float restart_time = (float(i) / float(pcount)) * lifetime;
+ float local_delta = p_delta;
+
+ if (randomness_ratio > 0.0) {
+ uint32_t seed = cycle;
+ if (restart_time >= time) {
+ seed -= uint32_t(1);
+ }
+ seed *= uint32_t(pcount);
+ seed += uint32_t(i);
+ float random = float(idhash(seed) % uint32_t(65536)) / 65536.0;
+ restart_time += randomness_ratio * random * 1.0 / float(pcount);
+ }
+
+ restart_time *= (1.0 - explosiveness_ratio);
+ bool restart = false;
+
+ if (time > prev_time) {
+ // restart_time >= prev_time is used so particles emit in the first frame they are processed
+
+ if (restart_time >= prev_time && restart_time < time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = (time - restart_time) * lifetime;
+ }
+ }
+
+ } else if (local_delta > 0.0) {
+ if (restart_time >= prev_time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = (1.0 - restart_time + time) * lifetime;
+ }
+
+ } else if (restart_time < time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = (time - restart_time) * lifetime;
+ }
+ }
+ }
+
+ if (restart) {
+
+ if (!emitting) {
+ p.active = false;
+ continue;
+ }
+ p.active = true;
+
+ /*float tex_linear_velocity = 0;
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
+ }*/
+
+ float tex_angle = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0);
+ }
+
+ float tex_anim_offset = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0);
+ }
+
+ p.seed = Math::rand();
+
+ p.angle_rand = Math::randf();
+ p.scale_rand = Math::randf();
+ p.hue_rot_rand = Math::randf();
+ p.anim_offset_rand = Math::randf();
+
+ float angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
+ Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
+ p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+
+ float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[1] = 0.0; //phase
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
+ p.transform = Transform2D();
+ p.time = 0;
+ p.base_color = Color(1, 1, 1, 1);
+
+ switch (emission_shape) {
+ case EMISSION_SHAPE_POINT: {
+ //do none
+ } break;
+ case EMISSION_SHAPE_CIRCLE: {
+ p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius;
+ } break;
+ case EMISSION_SHAPE_RECTANGLE: {
+ p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_rect_extents;
+ } break;
+ case EMISSION_SHAPE_POINTS:
+ case EMISSION_SHAPE_DIRECTED_POINTS: {
+
+ int pc = emission_points.size();
+ if (pc == 0)
+ break;
+
+ int random_idx = Math::rand() % pc;
+
+ p.transform[2] = emission_points.get(random_idx);
+
+ if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
+ p.velocity = emission_normals.get(random_idx);
+ }
+
+ if (emission_colors.size() == pc) {
+ p.base_color = emission_colors.get(random_idx);
+ }
+ } break;
+ }
+
+ if (!local_coords) {
+ p.velocity = velocity_xform.xform(p.velocity);
+ p.transform = emission_xform * p.transform;
+ }
+
+ } else if (!p.active) {
+ continue;
+ } else {
+
+ uint32_t alt_seed = p.seed;
+
+ p.time += local_delta;
+ p.custom[1] = p.time / lifetime;
+
+ float tex_linear_velocity = 0.0;
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]);
+ }
+ /*
+ float tex_orbit_velocity = 0.0;
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) {
+ tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]);
+ }
+ }
+*/
+ float tex_angular_velocity = 0.0;
+ if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
+ tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]);
+ }
+
+ float tex_linear_accel = 0.0;
+ if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
+ tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_tangential_accel = 0.0;
+ if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
+ tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_radial_accel = 0.0;
+ if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
+ tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_damping = 0.0;
+ if (curve_parameters[PARAM_DAMPING].is_valid()) {
+ tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]);
+ }
+
+ float tex_angle = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]);
+ }
+ float tex_anim_speed = 0.0;
+ if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
+ tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]);
+ }
+
+ float tex_anim_offset = 0.0;
+ if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
+ tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]);
+ }
+
+ Vector2 force = gravity;
+ Vector2 pos = p.transform[2];
+
+ //apply linear acceleration
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
+ //apply radial acceleration
+ Vector2 org = emission_xform[2];
+ Vector2 diff = pos - org;
+ force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
+ //apply tangential acceleration;
+ Vector2 yx = Vector2(diff.y, diff.x);
+ force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
+ //apply attractor forces
+ p.velocity += force * local_delta;
+ //orbit velocity
+#if 0
+ if (flags[FLAG_DISABLE_Z]) {
+
+ float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);
+ if (orbit_amount != 0.0) {
+ float ang = orbit_amount * DELTA * pi * 2.0;
+ mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));
+ TRANSFORM[3].xy -= diff.xy;
+ TRANSFORM[3].xy += rot * diff.xy;
+ }
+ }
+#endif
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ p.velocity = p.velocity.normalized() * tex_linear_velocity;
+ }
+
+ if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
+
+ float v = p.velocity.length();
+ float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ v -= damp * local_delta;
+ if (v < 0.0) {
+ p.velocity = Vector2();
+ } else {
+ p.velocity = p.velocity.normalized() * v;
+ }
+ }
+ float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
+ if (flags[FLAG_ANIM_LOOP]) {
+ p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop
+
+ } else {
+ p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only
+ }
+ }
+ //apply color
+ //apply hue rotation
+
+ float tex_scale = 1.0;
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]);
+ }
+
+ float tex_hue_variation = 0.0;
+ if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
+ tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]);
+ }
+
+ float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ float hue_rot_c = Math::cos(hue_rot_angle);
+ float hue_rot_s = Math::sin(hue_rot_angle);
+
+ Basis hue_rot_mat;
+ {
+ Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114);
+ Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886);
+ Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203);
+
+ for (int j = 0; j < 3; j++) {
+ hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s;
+ }
+ }
+
+ if (color_ramp.is_valid()) {
+ p.color = color_ramp->get_color_at_offset(p.custom[1]) * color;
+ } else {
+ p.color = color;
+ }
+
+ Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b));
+ p.color.r = color_rgb.x;
+ p.color.g = color_rgb.y;
+ p.color.b = color_rgb.z;
+
+ p.color *= p.base_color;
+
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (p.velocity.length() > 0.0) {
+
+ p.transform.elements[0] = p.velocity.normalized();
+ p.transform.elements[0] = p.transform.elements[1].tangent();
+ }
+
+ } else {
+ p.transform.elements[0] = Vector2(Math::cos(p.custom[0]), -Math::sin(p.custom[0]));
+ p.transform.elements[1] = Vector2(Math::sin(p.custom[0]), Math::cos(p.custom[0]));
+ }
+
+ //scale by scale
+ float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ if (base_scale == 0.0) base_scale = 0.000001;
+
+ p.transform.elements[0] *= base_scale;
+ p.transform.elements[1] *= base_scale;
+
+ p.transform[2] += p.velocity * local_delta;
+ }
+}
+
+void CPUParticles2D::_update_particle_data_buffer() {
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+
+ {
+
+ int pc = particles.size();
+
+ PoolVector<int>::Write ow;
+ int *order = NULL;
+
+ PoolVector<float>::Write w = particle_data.write();
+ PoolVector<Particle>::Read r = particles.read();
+ float *ptr = w.ptr();
+
+ Transform2D un_transform;
+ if (!local_coords) {
+ un_transform = get_global_transform().affine_inverse();
+ }
+
+ if (draw_order != DRAW_ORDER_INDEX) {
+ ow = particle_order.write();
+ order = ow.ptr();
+
+ for (int i = 0; i < pc; i++) {
+ order[i] = i;
+ }
+ if (draw_order == DRAW_ORDER_LIFETIME) {
+ SortArray<int, SortLifetime> sorter;
+ sorter.compare.particles = r.ptr();
+ sorter.sort(order, pc);
+ }
+ }
+
+ for (int i = 0; i < pc; i++) {
+
+ int idx = order ? order[i] : i;
+
+ Transform2D t = r[idx].transform;
+
+ if (!local_coords) {
+ t = un_transform * t;
+ }
+
+ if (r[idx].active) {
+
+ ptr[0] = t.elements[0][0];
+ ptr[1] = t.elements[1][0];
+ ptr[2] = 0;
+ ptr[3] = t.elements[2][0];
+ ptr[4] = t.elements[0][1];
+ ptr[5] = t.elements[1][1];
+ ptr[6] = 0;
+ ptr[7] = t.elements[2][1];
+
+ } else {
+ zeromem(ptr, sizeof(float) * 8);
+ }
+
+ Color c = r[idx].color;
+ uint8_t *data8 = (uint8_t *)&ptr[8];
+ data8[0] = CLAMP(c.r * 255.0, 0, 255);
+ data8[1] = CLAMP(c.g * 255.0, 0, 255);
+ data8[2] = CLAMP(c.b * 255.0, 0, 255);
+ data8[3] = CLAMP(c.a * 255.0, 0, 255);
+
+ ptr[9] = r[idx].custom[0];
+ ptr[10] = r[idx].custom[1];
+ ptr[11] = r[idx].custom[2];
+ ptr[12] = r[idx].custom[3];
+
+ ptr += 13;
+ }
+ }
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+}
+
+void CPUParticles2D::_update_render_thread() {
+
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+
+ VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+}
+
+void CPUParticles2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (is_processing_internal()) {
+
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ if (is_processing_internal()) {
+
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ }
+ }
+
+ if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
+ }
+
+ if (p_what == NOTIFICATION_DRAW) {
+
+ RID texrid;
+ if (texture.is_valid()) {
+ texrid = texture->get_rid();
+ }
+
+ RID normrid;
+ if (normalmap.is_valid()) {
+ normrid = normalmap->get_rid();
+ }
+
+ VS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid, normrid);
+ }
+
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+
+ if (particles.size() == 0)
+ return;
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ }
+
+ _update_particle_data_buffer();
+ }
+}
+
+void CPUParticles2D::convert_from_particles(Node *p_particles) {
+#if 0
+ Particles *particles = Object::cast_to<Particles>(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ set_emitting(particles->is_emitting());
+ set_amount(particles->get_amount());
+ set_lifetime(particles->get_lifetime());
+ set_one_shot(particles->get_one_shot());
+ set_pre_process_time(particles->get_pre_process_time());
+ set_explosiveness_ratio(particles->get_explosiveness_ratio());
+ set_randomness_ratio(particles->get_randomness_ratio());
+ set_use_local_coordinates(particles->get_use_local_coordinates());
+ set_fixed_fps(particles->get_fixed_fps());
+ set_fractional_delta(particles->get_fractional_delta());
+ set_speed_scale(particles->get_speed_scale());
+ set_draw_order(DrawOrder(particles->get_draw_order()));
+ set_mesh(particles->get_draw_pass_mesh(0));
+
+ Ref<ParticlesMaterial> material = particles->get_process_material();
+ if (material.is_null())
+ return;
+
+ set_spread(material->get_spread());
+ set_flatness(material->get_flatness());
+
+ set_color(material->get_color());
+
+ Ref<GradientTexture> gt = material->get_color_ramp();
+ if (gt.is_valid()) {
+ set_color_ramp(gt->get_gradient());
+ }
+
+ set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
+ set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
+ set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP));
+
+ set_emission_shape(EmissionShape(material->get_emission_shape()));
+ set_emission_sphere_radius(material->get_emission_sphere_radius());
+ set_emission_rect_extents(material->get_emission_rect_extents());
+
+ set_gravity(material->get_gravity());
+
+#define CONVERT_PARAM(m_param) \
+ set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ { \
+ Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
+ if (ctex.is_valid()) set_param_curve(m_param, ctex->get_curve()); \
+ } \
+ set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+
+ CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
+ CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
+ CONVERT_PARAM(PARAM_ORBIT_VELOCITY);
+ CONVERT_PARAM(PARAM_LINEAR_ACCEL);
+ CONVERT_PARAM(PARAM_RADIAL_ACCEL);
+ CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL);
+ CONVERT_PARAM(PARAM_DAMPING);
+ CONVERT_PARAM(PARAM_ANGLE);
+ CONVERT_PARAM(PARAM_SCALE);
+ CONVERT_PARAM(PARAM_HUE_VARIATION);
+ CONVERT_PARAM(PARAM_ANIM_SPEED);
+ CONVERT_PARAM(PARAM_ANIM_OFFSET);
+
+#undef CONVERT_PARAM
+#endif
+}
+
+void CPUParticles2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles2D::set_emitting);
+ ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles2D::set_amount);
+ ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles2D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles2D::set_one_shot);
+ ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles2D::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles2D::set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles2D::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles2D::set_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles2D::set_fixed_fps);
+ ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles2D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles2D::set_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles2D::is_emitting);
+ ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles2D::get_amount);
+ ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles2D::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles2D::get_one_shot);
+ ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles2D::get_pre_process_time);
+ ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles2D::get_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles2D::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles2D::get_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles2D::get_fixed_fps);
+ ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles2D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles2D::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles2D::set_draw_order);
+
+ ClassDB::bind_method(D_METHOD("get_draw_order"), &CPUParticles2D::get_draw_order);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &CPUParticles2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &CPUParticles2D::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normalmap", "normalmap"), &CPUParticles2D::set_normalmap);
+ ClassDB::bind_method(D_METHOD("get_normalmap"), &CPUParticles2D::get_normalmap);
+
+ ClassDB::bind_method(D_METHOD("restart"), &CPUParticles2D::restart);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ 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_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_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,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");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normalmap", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normalmap", "get_normalmap");
+
+ BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+
+ ////////////////////////////////
+
+ ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles2D::set_spread);
+ ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles2D::get_spread);
+
+ ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles2D::set_flatness);
+ ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles2D::get_flatness);
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles2D::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles2D::get_param);
+
+ ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles2D::set_param_randomness);
+ ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles2D::get_param_randomness);
+
+ ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles2D::set_param_curve);
+ ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles2D::get_param_curve);
+
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &CPUParticles2D::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &CPUParticles2D::get_color);
+
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles2D::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles2D::get_color_ramp);
+
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles2D::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles2D::get_particle_flag);
+
+ ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles2D::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles2D::get_emission_shape);
+
+ ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &CPUParticles2D::set_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &CPUParticles2D::get_emission_sphere_radius);
+
+ ClassDB::bind_method(D_METHOD("set_emission_rect_extents", "extents"), &CPUParticles2D::set_emission_rect_extents);
+ ClassDB::bind_method(D_METHOD("get_emission_rect_extents"), &CPUParticles2D::get_emission_rect_extents);
+
+ ClassDB::bind_method(D_METHOD("set_emission_points", "array"), &CPUParticles2D::set_emission_points);
+ ClassDB::bind_method(D_METHOD("get_emission_points"), &CPUParticles2D::get_emission_points);
+
+ ClassDB::bind_method(D_METHOD("set_emission_normals", "array"), &CPUParticles2D::set_emission_normals);
+ ClassDB::bind_method(D_METHOD("get_emission_normals"), &CPUParticles2D::get_emission_normals);
+
+ ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles2D::set_emission_colors);
+ ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles2D::get_emission_colors);
+
+ ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles2D::get_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles2D::set_gravity);
+
+ ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles);
+
+ ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles2D::_update_render_thread);
+
+ ADD_GROUP("Emission Shape", "emission_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "emission_rect_extents"), "set_emission_rect_extents", "get_emission_rect_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
+ ADD_GROUP("Flags", "flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_GROUP("Spread", "");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
+ ADD_GROUP("Gravity", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity");
+ ADD_GROUP("Initial Velocity", "initial_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
+ /*
+ ADD_GROUP("Orbit Velocity", "orbit_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
+*/
+ ADD_GROUP("Linear Accel", "linear_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
+ ADD_GROUP("Radial Accel", "radial_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
+ ADD_GROUP("Tangential Accel", "tangential_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
+ ADD_GROUP("Damping", "");
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
+ ADD_GROUP("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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
+ ADD_GROUP("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, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_GROUP("Color", "");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp");
+
+ ADD_GROUP("Hue Variation", "hue_");
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION);
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
+ ADD_GROUP("Animation", "anim_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP);
+
+ BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGLE);
+ BIND_ENUM_CONSTANT(PARAM_SCALE);
+ BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_CIRCLE);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_RECTANGLE);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
+}
+
+CPUParticles2D::CPUParticles2D() {
+
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+
+ mesh = VisualServer::get_singleton()->mesh_create();
+ multimesh = VisualServer::get_singleton()->multimesh_create();
+ VisualServer::get_singleton()->multimesh_set_mesh(multimesh, mesh);
+
+ set_emitting(true);
+ set_one_shot(false);
+ set_amount(8);
+ set_lifetime(1);
+ set_fixed_fps(0);
+ set_fractional_delta(true);
+ set_pre_process_time(0);
+ set_explosiveness_ratio(0);
+ set_randomness_ratio(0);
+ set_use_local_coordinates(true);
+
+ set_draw_order(DRAW_ORDER_INDEX);
+ set_speed_scale(1);
+
+ set_spread(45);
+ set_flatness(0);
+ set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1);
+ //set_param(PARAM_ORBIT_VELOCITY, 0);
+ set_param(PARAM_LINEAR_ACCEL, 0);
+ set_param(PARAM_RADIAL_ACCEL, 0);
+ set_param(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param(PARAM_DAMPING, 0);
+ set_param(PARAM_ANGLE, 0);
+ set_param(PARAM_SCALE, 1);
+ set_param(PARAM_HUE_VARIATION, 0);
+ set_param(PARAM_ANIM_SPEED, 0);
+ set_param(PARAM_ANIM_OFFSET, 0);
+ set_emission_shape(EMISSION_SHAPE_POINT);
+ set_emission_sphere_radius(1);
+ set_emission_rect_extents(Vector2(1, 1));
+
+ set_gravity(Vector2(0, 98.8));
+
+ for (int i = 0; i < PARAM_MAX; i++) {
+ set_param_randomness(Parameter(i), 0);
+ }
+
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = false;
+ }
+
+ set_color(Color(1, 1, 1, 1));
+
+#ifndef NO_THREADS
+ update_mutex = Mutex::create();
+#endif
+
+ _update_mesh_texture();
+}
+
+CPUParticles2D::~CPUParticles2D() {
+ VS::get_singleton()->free(multimesh);
+ VS::get_singleton()->free(mesh);
+
+#ifndef NO_THREADS
+ memdelete(update_mutex);
+#endif
+}
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
new file mode 100644
index 0000000000..dbe9f59748
--- /dev/null
+++ b/scene/2d/cpu_particles_2d.h
@@ -0,0 +1,289 @@
+/*************************************************************************/
+/* cpu_particles_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 CPU_PARTICLES_2D_H
+#define CPU_PARTICLES_2D_H
+
+#include "rid.h"
+#include "scene/2d/node_2d.h"
+#include "scene/resources/texture.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class CPUParticles2D : public Node2D {
+private:
+ GDCLASS(CPUParticles2D, Node2D);
+
+public:
+ enum DrawOrder {
+ DRAW_ORDER_INDEX,
+ DRAW_ORDER_LIFETIME,
+ };
+
+ enum Parameter {
+
+ PARAM_INITIAL_LINEAR_VELOCITY,
+ PARAM_ANGULAR_VELOCITY,
+ PARAM_ORBIT_VELOCITY,
+ PARAM_LINEAR_ACCEL,
+ PARAM_RADIAL_ACCEL,
+ PARAM_TANGENTIAL_ACCEL,
+ PARAM_DAMPING,
+ PARAM_ANGLE,
+ PARAM_SCALE,
+ PARAM_HUE_VARIATION,
+ PARAM_ANIM_SPEED,
+ PARAM_ANIM_OFFSET,
+ PARAM_MAX
+ };
+
+ enum Flags {
+ FLAG_ALIGN_Y_TO_VELOCITY,
+ FLAG_ANIM_LOOP,
+ FLAG_MAX
+ };
+
+ enum EmissionShape {
+ EMISSION_SHAPE_POINT,
+ EMISSION_SHAPE_CIRCLE,
+ EMISSION_SHAPE_RECTANGLE,
+ EMISSION_SHAPE_POINTS,
+ EMISSION_SHAPE_DIRECTED_POINTS,
+ };
+
+private:
+ bool emitting;
+
+ struct Particle {
+ Transform2D transform;
+ Color color;
+ float custom[4];
+ Vector2 velocity;
+ bool active;
+ float angle_rand;
+ float scale_rand;
+ float hue_rot_rand;
+ float anim_offset_rand;
+ float time;
+ Color base_color;
+
+ uint32_t seed;
+ };
+
+ float time;
+ float inactive_time;
+ float frame_remainder;
+ int cycle;
+
+ RID mesh;
+ RID multimesh;
+
+ PoolVector<Particle> particles;
+ PoolVector<float> particle_data;
+ PoolVector<int> particle_order;
+
+ struct SortLifetime {
+ const Particle *particles;
+
+ bool operator()(int p_a, int p_b) const {
+ return particles[p_a].time < particles[p_b].time;
+ }
+ };
+
+ struct SortAxis {
+ const Particle *particles;
+ Vector2 axis;
+ bool operator()(int p_a, int p_b) const {
+
+ return axis.dot(particles[p_a].transform[2]) < axis.dot(particles[p_b].transform[2]);
+ }
+ };
+
+ //
+
+ bool one_shot;
+
+ float lifetime;
+ float pre_process_time;
+ float explosiveness_ratio;
+ float randomness_ratio;
+ float speed_scale;
+ bool local_coords;
+ int fixed_fps;
+ bool fractional_delta;
+
+ DrawOrder draw_order;
+
+ Ref<Texture> texture;
+ Ref<Texture> normalmap;
+
+ ////////
+
+ float spread;
+ float flatness;
+
+ float parameters[PARAM_MAX];
+ float randomness[PARAM_MAX];
+
+ Ref<Curve> curve_parameters[PARAM_MAX];
+ Color color;
+ Ref<Gradient> color_ramp;
+
+ bool flags[FLAG_MAX];
+
+ EmissionShape emission_shape;
+ float emission_sphere_radius;
+ Vector2 emission_rect_extents;
+ PoolVector<Vector2> emission_points;
+ PoolVector<Vector2> emission_normals;
+ PoolVector<Color> emission_colors;
+ int emission_point_count;
+
+ bool anim_loop;
+ Vector2 gravity;
+
+ void _particles_process(float p_delta);
+ void _update_particle_data_buffer();
+
+ Mutex *update_mutex;
+
+ void _update_render_thread();
+
+ void _update_mesh_texture();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_emitting(bool p_emitting);
+ void set_amount(int p_amount);
+ void set_lifetime(float p_lifetime);
+ void set_one_shot(bool p_one_shot);
+ void set_pre_process_time(float p_time);
+ void set_explosiveness_ratio(float p_ratio);
+ void set_randomness_ratio(float p_ratio);
+ void set_visibility_aabb(const Rect2 &p_aabb);
+ void set_use_local_coordinates(bool p_enable);
+ void set_speed_scale(float p_scale);
+
+ bool is_emitting() const;
+ int get_amount() const;
+ float get_lifetime() const;
+ bool get_one_shot() const;
+ float get_pre_process_time() const;
+ float get_explosiveness_ratio() const;
+ float get_randomness_ratio() const;
+ Rect2 get_visibility_aabb() const;
+ bool get_use_local_coordinates() const;
+ float get_speed_scale() const;
+
+ void set_fixed_fps(int p_count);
+ int get_fixed_fps() const;
+
+ void set_fractional_delta(bool p_enable);
+ bool get_fractional_delta() const;
+
+ void set_draw_order(DrawOrder p_order);
+ DrawOrder get_draw_order() const;
+
+ void set_draw_passes(int p_count);
+ int get_draw_passes() const;
+
+ void set_texture(const Ref<Texture> &p_texture);
+ Ref<Texture> get_texture() const;
+
+ void set_normalmap(const Ref<Texture> &p_normalmap);
+ Ref<Texture> get_normalmap() const;
+
+ ///////////////////
+
+ void set_spread(float p_spread);
+ float get_spread() const;
+
+ void set_flatness(float p_flatness);
+ float get_flatness() const;
+
+ void set_param(Parameter p_param, float p_value);
+ float get_param(Parameter p_param) const;
+
+ void set_param_randomness(Parameter p_param, float p_value);
+ float get_param_randomness(Parameter p_param) const;
+
+ void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
+ Ref<Curve> get_param_curve(Parameter p_param) const;
+
+ void set_color(const Color &p_color);
+ Color get_color() const;
+
+ void set_color_ramp(const Ref<Gradient> &p_texture);
+ Ref<Gradient> get_color_ramp() const;
+
+ void set_particle_flag(Flags p_flag, bool p_enable);
+ bool get_particle_flag(Flags p_flag) const;
+
+ void set_emission_shape(EmissionShape p_shape);
+ void set_emission_sphere_radius(float p_radius);
+ void set_emission_rect_extents(Vector2 p_extents);
+ void set_emission_points(const PoolVector<Vector2> &p_points);
+ void set_emission_normals(const PoolVector<Vector2> &p_normals);
+ void set_emission_colors(const PoolVector<Color> &p_colors);
+ void set_emission_point_count(int p_count);
+
+ EmissionShape get_emission_shape() const;
+ float get_emission_sphere_radius() const;
+ Vector2 get_emission_rect_extents() const;
+ PoolVector<Vector2> get_emission_points() const;
+ PoolVector<Vector2> get_emission_normals() const;
+ PoolVector<Color> get_emission_colors() const;
+ int get_emission_point_count() const;
+
+ void set_gravity(const Vector2 &p_gravity);
+ Vector2 get_gravity() const;
+
+ virtual String get_configuration_warning() const;
+
+ void restart();
+
+ void convert_from_particles(Node *p_particles);
+
+ CPUParticles2D();
+ ~CPUParticles2D();
+};
+
+VARIANT_ENUM_CAST(CPUParticles2D::DrawOrder)
+VARIANT_ENUM_CAST(CPUParticles2D::Parameter)
+VARIANT_ENUM_CAST(CPUParticles2D::Flags)
+VARIANT_ENUM_CAST(CPUParticles2D::EmissionShape)
+
+#endif // CPU_PARTICLES_2D_H
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index 329382c034..7d5360c0e4 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -158,8 +158,8 @@ void Joint2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint2D::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a"), "set_node_a", "get_node_a");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b"), "set_node_b", "get_node_b");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject2D"), "set_node_a", "get_node_a");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject2D"), "set_node_b", "get_node_b");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bias", PROPERTY_HINT_RANGE, "0,0.9,0.001"), "set_bias", "get_bias");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
}
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 9a44eb31bb..f93c7d1f79 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -59,14 +59,22 @@ bool Light2D::_edit_use_pivot() const {
Rect2 Light2D::_edit_get_rect() const {
if (texture.is_null())
- return Node2D::_edit_get_rect();
+ return Rect2();
Size2 s = texture->get_size() * _scale;
return Rect2(texture_offset - s / 2.0, s);
}
bool Light2D::_edit_use_rect() const {
- return true;
+ return !texture.is_null();
+}
+
+Rect2 Light2D::get_anchorable_rect() const {
+ if (texture.is_null())
+ return Rect2();
+
+ Size2 s = texture->get_size() * _scale;
+ return Rect2(texture_offset - s / 2.0, s);
}
void Light2D::_update_light_visibility() {
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index 543805e329..40469cfbc8 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -94,6 +94,8 @@ public:
virtual Rect2 _edit_get_rect() const;
virtual bool _edit_use_rect() const;
+ virtual Rect2 get_anchorable_rect() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 3e61dd05f4..ad9775c0b7 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -239,7 +239,7 @@ void Line2D::_draw() {
{
PoolVector<Vector2>::Read points_read = _points.read();
for (int i = 0; i < len; ++i) {
- points[i] = points_read[i];
+ points.write[i] = points_read[i];
}
}
@@ -349,7 +349,7 @@ void Line2D::_bind_methods() {
ADD_GROUP("Fill", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile"), "set_texture_mode", "get_texture_mode");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile,Stretch"), "set_texture_mode", "get_texture_mode");
ADD_GROUP("Capping", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode");
@@ -368,6 +368,7 @@ void Line2D::_bind_methods() {
BIND_ENUM_CONSTANT(LINE_TEXTURE_NONE);
BIND_ENUM_CONSTANT(LINE_TEXTURE_TILE);
+ BIND_ENUM_CONSTANT(LINE_TEXTURE_STRETCH);
ClassDB::bind_method(D_METHOD("_gradient_changed"), &Line2D::_gradient_changed);
}
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 24c48982cd..6918018c12 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -52,8 +52,8 @@ public:
enum LineTextureMode {
LINE_TEXTURE_NONE = 0,
- LINE_TEXTURE_TILE
- // TODO STRETCH mode
+ LINE_TEXTURE_TILE,
+ LINE_TEXTURE_STRETCH
};
Line2D();
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 845788bada..a3f1b25e05 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -146,7 +146,9 @@ void LineBuilder::build() {
float current_distance1 = 0.f;
float total_distance = 0.f;
_interpolate_color = gradient != NULL;
- bool distance_required = _interpolate_color || texture_mode == Line2D::LINE_TEXTURE_TILE;
+ bool distance_required = _interpolate_color ||
+ texture_mode == Line2D::LINE_TEXTURE_TILE ||
+ texture_mode == Line2D::LINE_TEXTURE_STRETCH;
if (distance_required)
total_distance = calculate_total_distance(points);
if (_interpolate_color)
@@ -170,7 +172,7 @@ void LineBuilder::build() {
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx0 = 0.5f / tile_aspect;
}
- new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, 1.f, 1.f));
+ new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, fmin(uvx0 * 2, 1.f), 1.f));
total_distance += width;
current_distance0 += hw;
current_distance1 = current_distance0;
@@ -290,8 +292,10 @@ void LineBuilder::build() {
color1 = gradient->get_color_at_offset(current_distance1 / total_distance);
}
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx0 = current_distance0 / (width * tile_aspect);
uvx1 = current_distance1 / (width * tile_aspect);
+ } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
+ uvx0 = current_distance0 / total_distance;
+ uvx1 = current_distance1 / total_distance;
}
strip_add_quad(pos_up1, pos_down1, color1, uvx1);
@@ -301,7 +305,6 @@ void LineBuilder::build() {
u0 = u1;
f0 = f1;
pos0 = pos1;
- current_distance0 = current_distance1;
if (intersection_result == SEGMENT_INTERSECT) {
if (current_joint_mode == Line2D::LINE_JOINT_SHARP) {
pos_up0 = pos_up1;
@@ -378,6 +381,8 @@ void LineBuilder::build() {
}
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx1 = current_distance1 / (width * tile_aspect);
+ } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
+ uvx1 = current_distance1 / total_distance;
}
strip_add_quad(pos_up1, pos_down1, color1, uvx1);
@@ -386,7 +391,7 @@ void LineBuilder::build() {
if (end_cap_mode == Line2D::LINE_CAP_ROUND) {
// Note: color is not used in case we don't interpolate...
Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0);
- new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f, 0.f, 1.f, 1.f));
+ new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f / tile_aspect, 0.f, 1.0f / tile_aspect, 1.f));
}
}
diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h
index b1c62f84e2..edfdf97c47 100644
--- a/scene/2d/line_builder.h
+++ b/scene/2d/line_builder.h
@@ -33,8 +33,8 @@
#include "color.h"
#include "line_2d.h"
-#include "math_2d.h"
#include "scene/resources/color_ramp.h"
+#include "vector2.h"
class LineBuilder {
public:
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index 16e0386952..9eec8e6cc3 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -74,7 +74,7 @@ void Navigation2D::_navpoly_link(int p_id) {
Vector2 ep = nm.xform.xform(r[idx]);
center += ep;
e.point = _get_point(ep);
- p.edges[j] = e;
+ p.edges.write[j] = e;
int idxn = indices[(j + 1) % plen];
if (idxn < 0 || idxn >= len) {
@@ -119,17 +119,16 @@ void Navigation2D::_navpoly_link(int p_id) {
ConnectionPending pending;
pending.polygon = &p;
pending.edge = j;
- p.edges[j].P = C->get().pending.push_back(pending);
+ p.edges.write[j].P = C->get().pending.push_back(pending);
continue;
- //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
}
C->get().B = &p;
C->get().B_edge = j;
- C->get().A->edges[C->get().A_edge].C = &p;
- C->get().A->edges[C->get().A_edge].C_edge = j;
- p.edges[j].C = C->get().A;
- p.edges[j].C_edge = C->get().A_edge;
+ C->get().A->edges.write[C->get().A_edge].C = &p;
+ C->get().A->edges.write[C->get().A_edge].C_edge = j;
+ p.edges.write[j].C = C->get().A;
+ p.edges.write[j].C_edge = C->get().A_edge;
//connection successful.
}
}
@@ -144,8 +143,6 @@ void Navigation2D::_navpoly_unlink(int p_id) {
NavMesh &nm = navpoly_map[p_id];
ERR_FAIL_COND(!nm.linked);
- //print_line("UNLINK");
-
for (List<Polygon>::Element *E = nm.polygons.front(); E; E = E->next()) {
Polygon &p = E->get();
@@ -167,10 +164,10 @@ void Navigation2D::_navpoly_unlink(int p_id) {
} else if (C->get().B) {
//disconnect
- C->get().B->edges[C->get().B_edge].C = NULL;
- C->get().B->edges[C->get().B_edge].C_edge = -1;
- C->get().A->edges[C->get().A_edge].C = NULL;
- C->get().A->edges[C->get().A_edge].C_edge = -1;
+ C->get().B->edges.write[C->get().B_edge].C = NULL;
+ C->get().B->edges.write[C->get().B_edge].C_edge = -1;
+ C->get().A->edges.write[C->get().A_edge].C = NULL;
+ C->get().A->edges.write[C->get().A_edge].C_edge = -1;
if (C->get().A == &E->get()) {
@@ -187,11 +184,11 @@ void Navigation2D::_navpoly_unlink(int p_id) {
C->get().B = cp.polygon;
C->get().B_edge = cp.edge;
- C->get().A->edges[C->get().A_edge].C = cp.polygon;
- C->get().A->edges[C->get().A_edge].C_edge = cp.edge;
- cp.polygon->edges[cp.edge].C = C->get().A;
- cp.polygon->edges[cp.edge].C_edge = C->get().A_edge;
- cp.polygon->edges[cp.edge].P = NULL;
+ C->get().A->edges.write[C->get().A_edge].C = cp.polygon;
+ C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge;
+ cp.polygon->edges.write[cp.edge].C = C->get().A;
+ cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge;
+ cp.polygon->edges.write[cp.edge].P = NULL;
}
} else {
@@ -339,9 +336,8 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
Vector<Vector2> path;
path.resize(2);
- path[0] = begin_point;
- path[1] = end_point;
- //print_line("Direct Path");
+ path.write[0] = begin_point;
+ path.write[1] = end_point;
return path;
}
@@ -379,7 +375,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
while (!found_route) {
if (open_list.size() == 0) {
- //print_line("NOU OPEN LIST");
break;
}
//check open list
@@ -408,7 +403,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
for (int i = 0; i < es; i++) {
- Polygon::Edge &e = p->edges[i];
+ Polygon::Edge &e = p->edges.write[i];
if (!e.C)
continue;
@@ -526,7 +521,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
left_poly = p;
portal_left = left;
- //print_line("***ADVANCE LEFT");
} else {
apex_point = portal_right;
@@ -537,8 +531,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON)
path.push_back(apex_point);
skip = true;
- //print_line("addpoint left");
- //print_line("***CLIP LEFT");
}
}
@@ -547,7 +539,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
right_poly = p;
portal_right = right;
- //print_line("***ADVANCE RIGHT");
} else {
apex_point = portal_left;
@@ -557,8 +548,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
portal_left = apex_point;
if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON)
path.push_back(apex_point);
- //print_line("addpoint right");
- //print_line("***CLIP RIGHT");
}
}
@@ -586,7 +575,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) {
path.push_back(begin_point); // Add the begin point
} else {
- path[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point
+ path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point
}
path.invert();
@@ -594,7 +583,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) {
path.push_back(end_point); // Add the end point
} else {
- path[path.size() - 1] = end_point; // Replace last midpoint by the exact end point
+ path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point
}
return path;
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index 6e27bf1c1d..84b12b0bfe 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -91,7 +91,7 @@ void NavigationPolygon::_set_polygons(const Array &p_array) {
polygons.resize(p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- polygons[i].indices = p_array[i];
+ polygons.write[i].indices = p_array[i];
}
}
@@ -110,7 +110,7 @@ void NavigationPolygon::_set_outlines(const Array &p_array) {
outlines.resize(p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- outlines[i] = p_array[i];
+ outlines.write[i] = p_array[i];
}
rect_cache_dirty = true;
}
@@ -166,7 +166,7 @@ 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;
+ outlines.write[p_idx] = p_outline;
rect_cache_dirty = true;
}
@@ -257,7 +257,7 @@ void NavigationPolygon::make_polygons_from_outlines() {
TriangulatorPartition tpart;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- print_line("convex partition failed!");
+ ERR_PRINTS("NavigationPolygon: Convex partition failed!");
return;
}
@@ -432,8 +432,8 @@ void NavigationPolygonInstance::_notification(int p_what) {
{
PoolVector<Vector2>::Read vr = verts.read();
for (int i = 0; i < vsize; i++) {
- vertices[i] = vr[i];
- colors[i] = color;
+ vertices.write[i] = vr[i];
+ colors.write[i] = color;
}
}
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 3813bd96fe..7de72dc41d 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -130,7 +130,6 @@ void Node2D::_update_xform_values() {
void Node2D::_update_transform() {
- Transform2D mat(angle, pos);
_mat.set_rotation_and_scale(angle, _scale);
_mat.elements[2] = pos;
@@ -444,7 +443,7 @@ void Node2D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 1da1d44b17..7e824cdf75 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -30,10 +30,13 @@
#include "particles_2d.h"
-#include "engine.h"
-#include "scene/3d/particles.h"
+#include "scene/resources/particles_material.h"
#include "scene/scene_string_names.h"
+#ifdef TOOLS_ENABLED
+#include "core/engine.h"
+#endif
+
void Particles2D::set_emitting(bool p_emitting) {
VS::get_singleton()->particles_set_emitting(particles, p_emitting);
@@ -74,14 +77,14 @@ void Particles2D::set_randomness_ratio(float p_ratio) {
randomness_ratio = p_ratio;
VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
}
-void Particles2D::set_visibility_rect(const Rect2 &p_aabb) {
+void Particles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
- visibility_rect = p_aabb;
+ visibility_rect = p_visibility_rect;
AABB aabb;
- aabb.position.x = p_aabb.position.x;
- aabb.position.y = p_aabb.position.y;
- aabb.size.x = p_aabb.size.x;
- aabb.size.y = p_aabb.size.y;
+ aabb.position.x = p_visibility_rect.position.x;
+ aabb.position.y = p_visibility_rect.position.y;
+ aabb.size.x = p_visibility_rect.size.x;
+ aabb.size.y = p_visibility_rect.size.y;
VS::get_singleton()->particles_set_custom_aabb(particles, aabb);
@@ -114,7 +117,7 @@ void Particles2D::set_process_material(const Ref<Material> &p_material) {
process_material = p_material;
Ref<ParticlesMaterial> pm = p_material;
if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
- //likely a new material, modify it!
+ // Likely a new (3D) material, modify it to match 2D space
pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
pm->set_gravity(Vector3(0, 98, 0));
}
@@ -326,7 +329,7 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
- ClassDB::bind_method(D_METHOD("set_visibility_rect", "aabb"), &Particles2D::set_visibility_rect);
+ ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &Particles2D::set_visibility_rect);
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta);
@@ -372,13 +375,13 @@ void Particles2D::_bind_methods() {
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");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,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");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Drawing", "");
- ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
ADD_GROUP("Process Material", "process_");
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index f367095581..816149ba79 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PARTICLES_FRAME_H
-#define PARTICLES_FRAME_H
+#ifndef PARTICLES_2D_H
+#define PARTICLES_2D_H
+#include "rid.h"
#include "scene/2d/node_2d.h"
-#include "scene/resources/color_ramp.h"
#include "scene/resources/texture.h"
class Particles2D : public Node2D {
@@ -84,7 +84,7 @@ public:
void set_pre_process_time(float p_time);
void set_explosiveness_ratio(float p_ratio);
void set_randomness_ratio(float p_ratio);
- void set_visibility_rect(const Rect2 &p_aabb);
+ void set_visibility_rect(const Rect2 &p_visibility_rect);
void set_use_local_coordinates(bool p_enable);
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
@@ -132,4 +132,4 @@ public:
VARIANT_ENUM_CAST(Particles2D::DrawOrder)
-#endif // PARTICLES_FRAME_H
+#endif // PARTICLES_2D_H
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index feb11089d0..dc93414669 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -30,22 +30,13 @@
#include "physics_body_2d.h"
+#include "core/core_string_names.h"
#include "core/method_bind_ext.gen.inc"
#include "engine.h"
+#include "math_funcs.h"
#include "scene/scene_string_names.h"
void PhysicsBody2D::_notification(int p_what) {
-
- /*
- switch(p_what) {
-
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
-
- } break;
- }
- */
}
void PhysicsBody2D::_set_layers(uint32_t p_mask) {
@@ -186,28 +177,84 @@ real_t StaticBody2D::get_constant_angular_velocity() const {
return constant_angular_velocity;
}
+#ifndef DISABLE_DEPRECATED
void StaticBody2D::set_friction(real_t p_friction) {
+ if (p_friction == 1.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
- friction = p_friction;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, friction);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_friction(p_friction);
}
+
real_t StaticBody2D::get_friction() const {
- return friction;
+ ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 1;
+ }
+
+ return physics_material_override->get_friction();
}
void StaticBody2D::set_bounce(real_t p_bounce) {
+ if (p_bounce == 0.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
- bounce = p_bounce;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, bounce);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_bounce(p_bounce);
}
+
real_t StaticBody2D::get_bounce() const {
- return bounce;
+ ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 0;
+ }
+
+ return physics_material_override->get_bounce();
+}
+#endif // DISABLE_DEPRECATED
+
+void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const {
+ return physics_material_override;
}
void StaticBody2D::_bind_methods() {
@@ -216,29 +263,48 @@ void StaticBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity);
ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity);
ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity);
+
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &StaticBody2D::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &StaticBody2D::get_friction);
ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody2D::set_bounce);
ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody2D::get_bounce);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody2D::_reload_physics_characteristics);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
- 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");
+#ifndef DISABLE_DEPRECATED
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+#endif // DISABLE_DEPRECATED
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
}
StaticBody2D::StaticBody2D() :
PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) {
constant_angular_velocity = 0;
- bounce = 0;
- friction = 1;
}
StaticBody2D::~StaticBody2D() {
}
+void StaticBody2D::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
+ } else {
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
+}
+
void RigidBody2D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
@@ -297,13 +363,6 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
- /*if (obj) {
- if (body_in)
- print_line("in: "+String(obj->call("get_name")));
- else
- print_line("out: "+String(obj->call("get_name")));
- }*/
-
ERR_FAIL_COND(!body_in && !E);
if (body_in) {
@@ -345,13 +404,13 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
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);
if (in_scene)
- emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
+ emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
contact_monitor->body_map.erase(E);
}
if (node && in_scene) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, obj, p_body_shape, p_local_shape);
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, objid, node, p_body_shape, p_local_shape);
}
}
}
@@ -537,36 +596,90 @@ real_t RigidBody2D::get_inertia() const {
void RigidBody2D::set_weight(real_t p_weight) {
- set_mass(p_weight / real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10);
+ set_mass(p_weight / (real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10));
}
real_t RigidBody2D::get_weight() const {
- return mass * real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10;
+ return mass * (real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10);
}
+#ifndef DISABLE_DEPRECATED
void RigidBody2D::set_friction(real_t p_friction) {
+ if (p_friction == 1.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
- friction = p_friction;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, friction);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_friction(p_friction);
}
real_t RigidBody2D::get_friction() const {
- return friction;
+ ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 1;
+ }
+
+ return physics_material_override->get_friction();
}
void RigidBody2D::set_bounce(real_t p_bounce) {
+ if (p_bounce == 0.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
- bounce = p_bounce;
- Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, bounce);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_bounce(p_bounce);
}
real_t RigidBody2D::get_bounce() const {
- return bounce;
+ ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 0;
+ }
+
+ return physics_material_override->get_bounce();
+}
+#endif // DISABLE_DEPRECATED
+
+void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const {
+ return physics_material_override;
}
void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) {
@@ -690,11 +803,19 @@ int RigidBody2D::get_max_contacts_reported() const {
return max_contacts_reported;
}
+void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) {
+ Physics2DServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
+}
+
void RigidBody2D::apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) {
Physics2DServer::get_singleton()->body_apply_impulse(get_rid(), p_offset, p_impulse);
}
+void RigidBody2D::apply_torque_impulse(float p_torque) {
+ Physics2DServer::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque);
+}
+
void RigidBody2D::set_applied_force(const Vector2 &p_force) {
Physics2DServer::get_singleton()->body_set_applied_force(get_rid(), p_force);
@@ -715,11 +836,19 @@ float RigidBody2D::get_applied_torque() const {
return Physics2DServer::get_singleton()->body_get_applied_torque(get_rid());
};
+void RigidBody2D::add_central_force(const Vector2 &p_force) {
+ Physics2DServer::get_singleton()->body_add_central_force(get_rid(), p_force);
+}
+
void RigidBody2D::add_force(const Vector2 &p_offset, const Vector2 &p_force) {
Physics2DServer::get_singleton()->body_add_force(get_rid(), p_offset, p_force);
}
+void RigidBody2D::add_torque(const float p_torque) {
+ Physics2DServer::get_singleton()->body_add_torque(get_rid(), p_torque);
+}
+
void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) {
ccd_mode = p_mode;
@@ -837,11 +966,18 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody2D::set_weight);
ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody2D::get_weight);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &RigidBody2D::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &RigidBody2D::get_friction);
ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody2D::set_bounce);
ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody2D::get_bounce);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody2D::_reload_physics_characteristics);
ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale);
ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale);
@@ -871,7 +1007,9 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidBody2D::get_continuous_collision_detection_mode);
ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody2D::set_axis_velocity);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody2D::apply_central_impulse);
ClassDB::bind_method(D_METHOD("apply_impulse", "offset", "impulse"), &RigidBody2D::apply_impulse);
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidBody2D::apply_torque_impulse);
ClassDB::bind_method(D_METHOD("set_applied_force", "force"), &RigidBody2D::set_applied_force);
ClassDB::bind_method(D_METHOD("get_applied_force"), &RigidBody2D::get_applied_force);
@@ -879,7 +1017,9 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_applied_torque", "torque"), &RigidBody2D::set_applied_torque);
ClassDB::bind_method(D_METHOD("get_applied_torque"), &RigidBody2D::get_applied_torque);
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody2D::add_central_force);
ClassDB::bind_method(D_METHOD("add_force", "offset", "force"), &RigidBody2D::add_force);
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody2D::add_torque);
ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody2D::set_sleeping);
ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody2D::is_sleeping);
@@ -901,8 +1041,11 @@ void RigidBody2D::_bind_methods() {
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");
+#ifndef DISABLE_DEPRECATED
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+#endif // DISABLE_DEPRECATED
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode");
@@ -920,10 +1063,10 @@ void RigidBody2D::_bind_methods() {
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")));
- ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body")));
- ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), 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", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("sleeping_state_changed"));
BIND_ENUM_CONSTANT(MODE_RIGID);
@@ -941,9 +1084,7 @@ RigidBody2D::RigidBody2D() :
mode = MODE_RIGID;
- bounce = 0;
mass = 1;
- friction = 1;
gravity_scale = 1;
linear_damp = -1;
@@ -969,13 +1110,23 @@ RigidBody2D::~RigidBody2D() {
memdelete(contact_monitor);
}
+void RigidBody2D::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
+ } else {
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
+}
+
//////////////////////////
-Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia) {
+Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -989,11 +1140,48 @@ Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p
return Ref<KinematicCollision2D>();
}
-bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision) {
+bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
+
+ Physics2DServer::SeparationResult sep_res[8]; //max 8 rays
+
+ Transform2D gt = get_global_transform();
+
+ Vector2 recover;
+ int hits = Physics2DServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ int deepest = -1;
+ float deepest_depth;
+ for (int i = 0; i < hits; i++) {
+ if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
+ deepest = i;
+ deepest_depth = sep_res[i].collision_depth;
+ }
+ }
+
+ gt.elements[2] += recover;
+ set_global_transform(gt);
+
+ if (deepest != -1) {
+ r_collision.collider = sep_res[deepest].collider_id;
+ r_collision.collider_metadata = sep_res[deepest].collider_metadata;
+ r_collision.collider_shape = sep_res[deepest].collider_shape;
+ r_collision.collider_vel = sep_res[deepest].collider_velocity;
+ r_collision.collision = sep_res[deepest].collision_point;
+ r_collision.normal = sep_res[deepest].collision_normal;
+ r_collision.local_shape = sep_res[deepest].collision_local_shape;
+ r_collision.travel = recover;
+ r_collision.remainder = Vector2();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
Transform2D gt = get_global_transform();
Physics2DServer::MotionResult result;
- bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result);
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes);
if (colliding) {
r_collision.collider_metadata = result.collider_metadata;
@@ -1002,73 +1190,121 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
r_collision.collision = result.collision_point;
r_collision.normal = result.collision_normal;
r_collision.collider = result.collider_id;
+ r_collision.collider_rid = result.collider;
r_collision.travel = result.motion;
r_collision.remainder = result.remainder;
r_collision.local_shape = result.collision_local_shape;
}
- gt.elements[2] += result.motion;
- set_global_transform(gt);
+ if (!p_test_only) {
+ gt.elements[2] += result.motion;
+ set_global_transform(gt);
+ }
return colliding;
}
-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) {
+//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+#define FLOOR_ANGLE_THRESHOLD 0.01
+
+Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) {
- Vector2 motion = (floor_velocity + p_linear_velocity) * get_physics_process_delta_time();
+ Vector2 floor_motion = floor_velocity;
+ if (on_floor && on_floor_body.is_valid()) {
+ //this approach makes sure there is less delay between the actual body velocity and the one we saved
+ Physics2DDirectBodyState *bs = Physics2DServer::get_singleton()->body_get_direct_state(on_floor_body);
+ if (bs) {
+ floor_motion = bs->get_linear_velocity();
+ }
+ }
+
+ Vector2 motion = (floor_motion + p_linear_velocity) * get_physics_process_delta_time();
Vector2 lv = p_linear_velocity;
on_floor = false;
+ on_floor_body = RID();
on_ceiling = false;
on_wall = false;
colliders.clear();
floor_velocity = Vector2();
+ Vector2 lv_n = p_linear_velocity.normalized();
+
while (p_max_slides) {
Collision collision;
+ bool found_collision = false;
+
+ for (int i = 0; i < 2; i++) {
+ bool collided;
+ if (i == 0) { //collide
+ collided = move_and_collide(motion, p_infinite_inertia, collision);
+ if (!collided) {
+ motion = Vector2(); //clear because no collision happened and motion completed
+ }
+ } else { //separate raycasts (if any)
+ collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ if (collided) {
+ collision.remainder = motion; //keep
+ collision.travel = Vector2();
+ }
+ }
- bool collided = move_and_collide(motion, p_infinite_inertia, collision);
-
- if (collided) {
-
- motion = collision.remainder;
-
- if (p_floor_direction == Vector2()) {
- //all is a wall
- on_wall = true;
- } else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ if (collided) {
+ found_collision = true;
+ }
- on_floor = true;
- floor_velocity = collision.collider_vel;
+ if (collided) {
- Vector2 rel_v = lv - floor_velocity;
- Vector2 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v);
+ colliders.push_back(collision);
+ motion = collision.remainder;
- if (collision.travel.length() < 1 && hv.length() < p_slope_stop_min_velocity) {
- Transform2D gt = get_global_transform();
- gt.elements[2] -= collision.travel;
- set_global_transform(gt);
- return Vector2();
+ bool is_on_slope = false;
+ if (p_floor_direction == Vector2()) {
+ //all is a wall
+ on_wall = true;
+ } else {
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
+
+ on_floor = true;
+ on_floor_body = collision.collider_rid;
+ floor_velocity = collision.collider_vel;
+
+ if (p_stop_on_slope) {
+ if (Vector2() == lv_n + p_floor_direction) {
+ Transform2D gt = get_global_transform();
+ gt.elements[2] -= collision.travel;
+ set_global_transform(gt);
+ return Vector2();
+ }
+ }
+
+ is_on_slope = true;
+
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
}
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
- on_ceiling = true;
+ }
+
+ if (p_stop_on_slope && is_on_slope) {
+ motion = motion.slide(p_floor_direction);
+ lv = lv.slide(p_floor_direction);
} else {
- on_wall = true;
+ Vector2 n = collision.normal;
+ motion = motion.slide(n);
+ lv = lv.slide(n);
}
}
- Vector2 n = collision.normal;
- motion = motion.slide(n);
- lv = lv.slide(n);
-
- colliders.push_back(collision);
+ if (p_stop_on_slope)
+ break;
+ }
- } else {
+ if (!found_collision) {
break;
}
-
p_max_slides--;
if (motion == Vector2())
break;
@@ -1077,6 +1313,31 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
return lv;
}
+Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) {
+
+ bool was_on_floor = on_floor;
+
+ Vector2 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_infinite_inertia, p_stop_on_slope, p_max_slides, p_floor_max_angle);
+ if (!was_on_floor || p_snap == Vector2()) {
+ return ret;
+ }
+
+ Collision col;
+ Transform2D gt = get_global_transform();
+
+ if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) {
+ gt.elements[2] += col.travel;
+ if (p_floor_direction != Vector2() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
+ on_floor = true;
+ on_floor_body = col.collider_rid;
+ floor_velocity = col.collider_vel;
+ }
+ set_global_transform(gt);
+ }
+
+ return ret;
+}
+
bool KinematicBody2D::is_on_floor() const {
return on_floor;
@@ -1130,18 +1391,68 @@ Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) {
}
if (slide_colliders[p_bounce].is_null()) {
- slide_colliders[p_bounce].instance();
- slide_colliders[p_bounce]->owner = this;
+ slide_colliders.write[p_bounce].instance();
+ slide_colliders.write[p_bounce]->owner = this;
}
- slide_colliders[p_bounce]->collision = colliders[p_bounce];
+ slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
return slide_colliders[p_bounce];
}
+void KinematicBody2D::set_sync_to_physics(bool p_enable) {
+
+ if (sync_to_physics == p_enable) {
+ return;
+ }
+ sync_to_physics = p_enable;
+ if (p_enable) {
+ Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ set_only_update_transform_changes(true);
+ set_notify_local_transform(true);
+ } else {
+ Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
+ set_only_update_transform_changes(false);
+ set_notify_local_transform(false);
+ }
+}
+
+bool KinematicBody2D::is_sync_to_physics_enabled() const {
+ return sync_to_physics;
+}
+
+void KinematicBody2D::_direct_state_changed(Object *p_state) {
+
+ if (!sync_to_physics)
+ return;
+
+ Physics2DDirectBodyState *state = Object::cast_to<Physics2DDirectBodyState>(p_state);
+
+ last_valid_transform = state->get_transform();
+ set_notify_local_transform(false);
+ set_global_transform(last_valid_transform);
+ set_notify_local_transform(true);
+}
+
+void KinematicBody2D::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ last_valid_transform = get_global_transform();
+ }
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ //used by sync to physics, send the new transform to the physics
+ Transform2D new_transform = get_global_transform();
+ Physics2DServer::get_singleton()->body_set_state(get_rid(), Physics2DServer::BODY_STATE_TRANSFORM, new_transform);
+ //but then revert changes
+ set_notify_local_transform(false);
+ set_global_transform(last_valid_transform);
+ set_notify_local_transform(true);
+ }
+}
void KinematicBody2D::_bind_methods() {
- 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("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move);
@@ -1156,7 +1467,13 @@ void KinematicBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody2D::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody2D::_get_slide_collision);
+ ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody2D::set_sync_to_physics);
+ ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody2D::is_sync_to_physics_enabled);
+
+ ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody2D::_direct_state_changed);
+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
}
KinematicBody2D::KinematicBody2D() :
@@ -1167,6 +1484,7 @@ KinematicBody2D::KinematicBody2D() :
on_floor = false;
on_ceiling = false;
on_wall = false;
+ sync_to_physics = false;
}
KinematicBody2D::~KinematicBody2D() {
if (motion_cache.is_valid()) {
@@ -1175,7 +1493,7 @@ KinematicBody2D::~KinematicBody2D() {
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
- slide_colliders[i]->owner = NULL;
+ slide_colliders.write[i]->owner = NULL;
}
}
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 0fda3c5c05..852963a721 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -32,6 +32,7 @@
#define PHYSICS_BODY_2D_H
#include "scene/2d/collision_object_2d.h"
+#include "scene/resources/physics_material.h"
#include "servers/physics_2d_server.h"
#include "vset.h"
@@ -79,18 +80,21 @@ class StaticBody2D : public PhysicsBody2D {
Vector2 constant_linear_velocity;
real_t constant_angular_velocity;
- real_t bounce;
- real_t friction;
+ Ref<PhysicsMaterial> physics_material_override;
protected:
static void _bind_methods();
public:
+#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
+#endif
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
void set_constant_linear_velocity(const Vector2 &p_vel);
void set_constant_angular_velocity(real_t p_vel);
@@ -100,6 +104,9 @@ public:
StaticBody2D();
~StaticBody2D();
+
+private:
+ void _reload_physics_characteristics();
};
class RigidBody2D : public PhysicsBody2D {
@@ -125,9 +132,8 @@ private:
Physics2DDirectBodyState *state;
Mode mode;
- real_t bounce;
real_t mass;
- real_t friction;
+ Ref<PhysicsMaterial> physics_material_override;
real_t gravity_scale;
real_t linear_damp;
real_t angular_damp;
@@ -204,11 +210,16 @@ public:
void set_weight(real_t p_weight);
real_t get_weight() const;
+#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
+#endif
+
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
void set_gravity_scale(real_t p_gravity_scale);
real_t get_gravity_scale() const;
@@ -245,7 +256,9 @@ public:
void set_continuous_collision_detection_mode(CCDMode p_mode);
CCDMode get_continuous_collision_detection_mode() const;
+ void apply_central_impulse(const Vector2 &p_impulse);
void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse);
+ void apply_torque_impulse(float p_torque);
void set_applied_force(const Vector2 &p_force);
Vector2 get_applied_force() const;
@@ -253,7 +266,9 @@ public:
void set_applied_torque(const float p_torque);
float get_applied_torque() const;
+ void add_central_force(const Vector2 &p_force);
void add_force(const Vector2 &p_offset, const Vector2 &p_force);
+ void add_torque(float p_torque);
Array get_colliding_bodies() const; //function for script
@@ -261,6 +276,9 @@ public:
RigidBody2D();
~RigidBody2D();
+
+private:
+ void _reload_physics_characteristics();
};
VARIANT_ENUM_CAST(RigidBody2D::Mode);
@@ -276,6 +294,7 @@ public:
Vector2 normal;
Vector2 collider_vel;
ObjectID collider;
+ RID collider_rid;
int collider_shape;
Variant collider_metadata;
Vector2 remainder;
@@ -287,29 +306,40 @@ private:
float margin;
Vector2 floor_velocity;
+ RID on_floor_body;
bool on_floor;
bool on_ceiling;
bool on_wall;
+ bool sync_to_physics;
+
Vector<Collision> colliders;
Vector<Ref<KinematicCollision2D> > slide_colliders;
Ref<KinematicCollision2D> motion_cache;
_FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const;
- Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
+ Transform2D last_valid_transform;
+ void _direct_state_changed(Object *p_state);
+
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
- bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision);
+ bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false);
+
bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia);
+ bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+
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), 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));
+ Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
+ Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, 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;
@@ -318,6 +348,9 @@ public:
int get_slide_count() const;
Collision get_slide_collision(int p_bounce) const;
+ void set_sync_to_physics(bool p_enable);
+ bool is_sync_to_physics_enabled() const;
+
KinematicBody2D();
~KinematicBody2D();
};
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 4d6ebc81c3..fc0741cc5c 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -29,8 +29,10 @@
/*************************************************************************/
#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;
@@ -113,7 +115,7 @@ void Polygon2D::_notification(int p_what) {
PoolVector<Vector2>::Read polyr = polygon.read();
for (int i = 0; i < len; i++) {
- points[i] = polyr[i] + offset;
+ points.write[i] = polyr[i] + offset;
}
}
@@ -153,18 +155,18 @@ void Polygon2D::_notification(int p_what) {
SWAP(ep[1], ep[4]);
SWAP(ep[2], ep[3]);
SWAP(ep[5], ep[0]);
- SWAP(ep[6], points[highest_idx]);
+ SWAP(ep[6], points.write[highest_idx]);
}
points.resize(points.size() + 7);
for (int i = points.size() - 1; i >= highest_idx + 7; i--) {
- points[i] = points[i - 7];
+ points.write[i] = points[i - 7];
}
for (int i = 0; i < 7; i++) {
- points[highest_idx + i + 1] = ep[i];
+ points.write[highest_idx + i + 1] = ep[i];
}
len = points.size();
@@ -182,12 +184,12 @@ void Polygon2D::_notification(int p_what) {
PoolVector<Vector2>::Read uvr = uv.read();
for (int i = 0; i < len; i++) {
- uvs[i] = texmat.xform(uvr[i]) / tex_size;
+ uvs.write[i] = texmat.xform(uvr[i]) / tex_size;
}
} else {
for (int i = 0; i < len; i++) {
- uvs[i] = texmat.xform(points[i]) / tex_size;
+ uvs.write[i] = texmat.xform(points[i]) / tex_size;
}
}
}
@@ -251,7 +253,6 @@ void Polygon2D::_notification(int p_what) {
//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]));
}
}
}
@@ -262,10 +263,10 @@ void Polygon2D::_notification(int p_what) {
{
PoolVector<Color>::Read color_r = vertex_colors.read();
for (int i = 0; i < color_len && i < len; i++) {
- colors[i] = color_r[i];
+ colors.write[i] = color_r[i];
}
for (int i = color_len; i < len; i++) {
- colors[i] = color;
+ colors.write[i] = color;
}
}
@@ -333,18 +334,16 @@ void Polygon2D::_notification(int p_what) {
Vector<Vector2> vertices;
vertices.resize(loop.size());
for (int j = 0; j < vertices.size(); j++) {
- vertices[j] = points[loop[j]];
+ vertices.write[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]];
+ indices.write[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());
}
@@ -538,12 +537,12 @@ void Polygon2D::clear_bones() {
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;
+ bone_weights.write[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;
+ bone_weights.write[p_index].path = p_path;
update();
}
@@ -646,10 +645,10 @@ 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_degrees", 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, "-1080,1080,0.1,or_lesser,or_greater"), "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_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
ADD_GROUP("Invert", "invert_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert");
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 255d2d38d5..d9b3cb07fc 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -209,7 +209,7 @@ void RayCast2D::_update_raycast_state() {
Physics2DDirectSpaceState::RayResult rr;
- if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask)) {
+ if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
collided = true;
against = rr.collider_id;
@@ -218,6 +218,8 @@ void RayCast2D::_update_raycast_state() {
against_shape = rr.shape;
} else {
collided = false;
+ against = 0;
+ against_shape = 0;
}
}
@@ -258,6 +260,26 @@ void RayCast2D::clear_exceptions() {
exclude.clear();
}
+void RayCast2D::set_collide_with_areas(bool p_clip) {
+
+ collide_with_areas = p_clip;
+}
+
+bool RayCast2D::is_collide_with_areas_enabled() const {
+
+ return collide_with_areas;
+}
+
+void RayCast2D::set_collide_with_bodies(bool p_clip) {
+
+ collide_with_bodies = p_clip;
+}
+
+bool RayCast2D::is_collide_with_bodies_enabled() const {
+
+ return collide_with_bodies;
+}
+
void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled);
@@ -291,10 +313,20 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast2D::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast2D::get_exclude_parent_body);
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast2D::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast2D::is_collide_with_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast2D::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast2D::is_collide_with_bodies_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cast_to"), "set_cast_to", "get_cast_to");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Collide With", "collide_with");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
}
RayCast2D::RayCast2D() {
@@ -306,4 +338,6 @@ RayCast2D::RayCast2D() {
collision_mask = 1;
cast_to = Vector2(0, 50);
exclude_parent_body = true;
+ collide_with_bodies = true;
+ collide_with_areas = false;
}
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 0850cdc7cc..a438be87b6 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -49,12 +49,21 @@ class RayCast2D : public Node2D {
Vector2 cast_to;
+ bool collide_with_areas;
+ bool collide_with_bodies;
+
protected:
void _notification(int p_what);
void _update_raycast_state();
static void _bind_methods();
public:
+ void set_collide_with_areas(bool p_clip);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_collide_with_bodies(bool p_clip);
+ bool is_collide_with_bodies_enabled() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index da764e032b..f0274e5206 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -67,7 +67,7 @@ void RemoteTransform2D::_update_remote() {
} else {
Transform2D n_trans = n->get_global_transform();
Transform2D our_trans = get_global_transform();
- Vector2 n_scale = n->get_global_scale();
+ Vector2 n_scale = n->get_scale();
if (!update_remote_position)
our_trans.set_origin(n_trans.get_origin());
@@ -131,8 +131,10 @@ void RemoteTransform2D::_notification(int p_what) {
void RemoteTransform2D::set_remote_node(const NodePath &p_remote_node) {
remote_node = p_remote_node;
- if (is_inside_tree())
+ if (is_inside_tree()) {
_update_cache();
+ _update_remote();
+ }
update_configuration_warning();
}
@@ -144,6 +146,7 @@ NodePath RemoteTransform2D::get_remote_node() const {
void RemoteTransform2D::set_use_global_coordinates(const bool p_enable) {
use_global_coordinates = p_enable;
+ _update_remote();
}
bool RemoteTransform2D::get_use_global_coordinates() const {
@@ -201,7 +204,7 @@ void RemoteTransform2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform2D::set_update_scale);
ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform2D::get_update_scale);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path"), "set_remote_node", "get_remote_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_remote_node", "get_remote_node");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");
ADD_GROUP("Update", "update_");
diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp
index 9480f18176..45f63fd5bf 100644
--- a/scene/2d/screen_button.cpp
+++ b/scene/2d/screen_button.cpp
@@ -324,19 +324,21 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
}
Rect2 TouchScreenButton::_edit_get_rect() const {
-
- if (texture.is_null())
- return Rect2(0, 0, 1, 1);
- /*
if (texture.is_null())
return CanvasItem::_edit_get_rect();
- */
return Rect2(Size2(), texture->get_size());
}
bool TouchScreenButton::_edit_use_rect() const {
- return true;
+ return !texture.is_null();
+}
+
+Rect2 TouchScreenButton::get_anchorable_rect() const {
+ if (texture.is_null())
+ return CanvasItem::get_anchorable_rect();
+
+ return Rect2(Size2(), texture->get_size());
}
void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h
index b2fafcc93d..3e8adc2e5e 100644
--- a/scene/2d/screen_button.h
+++ b/scene/2d/screen_button.h
@@ -103,8 +103,9 @@ public:
bool is_pressed() const;
- Rect2 _edit_get_rect() const;
+ virtual Rect2 _edit_get_rect() const;
virtual bool _edit_use_rect() const;
+ virtual Rect2 get_anchorable_rect() const;
TouchScreenButton();
};
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 8ceffb3c27..2c362f1b31 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -191,13 +191,13 @@ void Skeleton2D::_update_bone_setup() {
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;
+ bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
+ bones.write[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;
+ bones.write[i].parent_index = parent_bone->skeleton_index;
} else {
- bones[i].parent_index = -1;
+ bones.write[i].parent_index = -1;
}
}
@@ -230,9 +230,9 @@ void Skeleton2D::_update_transform() {
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();
+ bones.write[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();
+ bones.write[i].accum_transform = bones[i].bone->get_transform();
}
}
@@ -288,7 +288,7 @@ void Skeleton2D::_bind_methods() {
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_bone", "idx"), &Skeleton2D::get_bone);
ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
}
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index 64d0771fab..bb5990fa79 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -63,9 +63,16 @@ Rect2 Sprite::_edit_get_rect() const {
}
bool Sprite::_edit_use_rect() const {
+ if (texture.is_null())
+ return false;
+
return true;
}
+Rect2 Sprite::get_anchorable_rect() const {
+ return get_rect();
+}
+
void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
Rect2 base_rect;
@@ -291,6 +298,11 @@ int Sprite::get_hframes() const {
bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ return is_pixel_opaque(p_point);
+}
+
+bool Sprite::is_pixel_opaque(const Point2 &p_point) const {
+
if (texture.is_null())
return false;
@@ -309,32 +321,6 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
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) {
@@ -356,21 +342,14 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
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;
+ return texture->is_pixel_opaque((int)q.x, (int)q.y);
}
Rect2 Sprite::get_rect() const {
if (texture.is_null())
return Rect2(0, 0, 1, 1);
- /*
- if (texture.is_null())
- return CanvasItem::_edit_get_rect();
- */
Size2i s;
@@ -434,6 +413,8 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite::set_region);
ClassDB::bind_method(D_METHOD("is_region"), &Sprite::is_region);
+ ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite::is_pixel_opaque);
+
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect);
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index 609ad8bb34..ab444f89fc 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -75,6 +75,8 @@ public:
virtual bool _edit_use_pivot() const;
virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+ bool is_pixel_opaque(const Point2 &p_point) const;
+
virtual Rect2 _edit_get_rect() const;
virtual bool _edit_use_rect() const;
@@ -115,6 +117,7 @@ public:
int get_hframes() const;
Rect2 get_rect() const;
+ virtual Rect2 get_anchorable_rect() const;
Sprite();
~Sprite();
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 1d60037287..8a2fdbacfa 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -62,7 +62,7 @@ void TileMap::_notification(int p_what) {
pending_update = true;
_recreate_quadrants();
- _update_dirty_quadrants();
+ update_dirty_quadrants();
RID space = get_world_2d()->get_space();
_update_quadrant_transform();
_update_quadrant_space(space);
@@ -245,7 +245,7 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const
xform.elements[2].y += offset.y;
}
-void TileMap::_update_dirty_quadrants() {
+void TileMap::update_dirty_quadrants() {
if (!pending_update)
return;
@@ -368,7 +368,7 @@ void TileMap::_update_dirty_quadrants() {
}
Rect2 r = tile_set->tile_get_region(c.id);
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_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);
@@ -491,7 +491,7 @@ void TileMap::_update_dirty_quadrants() {
if (navigation) {
Ref<NavigationPolygon> navpoly;
Vector2 npoly_ofs;
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) {
navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
npoly_ofs = Vector2();
} else {
@@ -529,8 +529,8 @@ void TileMap::_update_dirty_quadrants() {
{
PoolVector<Vector2>::Read vr = navigation_polygon_vertices.read();
for (int i = 0; i < vsize; i++) {
- vertices[i] = vr[i];
- colors[i] = debug_navigation_color;
+ vertices.write[i] = vr[i];
+ colors.write[i] = debug_navigation_color;
}
}
@@ -563,7 +563,7 @@ void TileMap::_update_dirty_quadrants() {
}
Ref<OccluderPolygon2D> occluder;
- if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_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);
@@ -631,11 +631,7 @@ void TileMap::_recompute_rect_cache() {
r_total = r_total.merge(r);
}
- if (r_total == Rect2()) {
- rect_cache = Rect2(-10, -10, 20, 20);
- } else {
- rect_cache = r_total.grow(MAX(cell_size.x, cell_size.y) * _get_quadrant_size());
- }
+ rect_cache = r_total;
item_rect_changed();
@@ -721,7 +717,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool updat
return;
if (update) {
- _update_dirty_quadrants();
+ call_deferred("update_dirty_quadrants");
}
}
@@ -730,7 +726,7 @@ void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_
set_cell(p_pos.x, p_pos.y, p_tile, p_flip_x, p_flip_y, p_transpose);
}
-void TileMap::set_celld(const Vector2 &p_pos, const Dictionary &p_data) {
+void TileMap::_set_celld(const Vector2 &p_pos, const Dictionary &p_data) {
set_cell(p_pos.x, p_pos.y, p_data["id"], p_data["flip_h"], p_data["flip_y"], p_data["transpose"], p_data["auto_coord"]);
}
@@ -840,7 +836,7 @@ void TileMap::update_cell_bitmask(int p_x, int 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_tile_mode(id) == TileSet::AUTO_TILE) {
+ if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_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))) {
@@ -1026,7 +1022,7 @@ void TileMap::_recreate_quadrants() {
Q->get().cells.insert(E->key());
_make_quadrant_dirty(Q, false);
}
- _update_dirty_quadrants();
+ update_dirty_quadrants();
}
void TileMap::_clear_quadrants() {
@@ -1153,15 +1149,10 @@ PoolVector<int> TileMap::_get_tile_data() const {
}
Rect2 TileMap::_edit_get_rect() const {
-
- const_cast<TileMap *>(this)->_update_dirty_quadrants();
+ const_cast<TileMap *>(this)->update_dirty_quadrants();
return rect_cache;
}
-bool TileMap::_edit_use_rect() const {
- return true;
-}
-
void TileMap::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
@@ -1621,7 +1612,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("set_cellv", "position", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_celld", "data"), &TileMap::set_celld);
+ ClassDB::bind_method(D_METHOD("_set_celld", "position", "data"), &TileMap::_set_celld);
ClassDB::bind_method(D_METHOD("get_cell", "x", "y"), &TileMap::get_cell);
ClassDB::bind_method(D_METHOD("get_cellv", "position"), &TileMap::get_cellv);
ClassDB::bind_method(D_METHOD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped);
@@ -1640,7 +1631,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_clear_quadrants"), &TileMap::_clear_quadrants);
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_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()));
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 3ddb143f4a..55db33837f 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -191,7 +191,6 @@ private:
void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update = true);
void _recreate_quadrants();
void _clear_quadrants();
- void _update_dirty_quadrants();
void _update_quadrant_space(const RID &p_space);
void _update_quadrant_transform();
void _recompute_rect_cache();
@@ -224,6 +223,8 @@ public:
INVALID_CELL = -1
};
+ virtual Rect2 _edit_get_rect() const;
+
void set_tileset(const Ref<TileSet> &p_tileset);
Ref<TileSet> get_tileset() const;
@@ -241,19 +242,18 @@ public:
void set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord);
Vector2 get_cell_autotile_coord(int p_x, int p_y) const;
- void set_celld(const Vector2 &p_pos, const Dictionary &p_data);
+ void _set_celld(const Vector2 &p_pos, const Dictionary &p_data);
void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false);
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();
+ void update_dirty_quadrants();
+
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 6ea980ec97..40a1029201 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -243,7 +243,7 @@ void Area::_clear_monitoring() {
emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->key(), node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
}
- emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
+ emit_signal(SceneStringNames::get_singleton()->body_exited, 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);
@@ -699,10 +699,10 @@ void Area::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area::set_reverb_uniformity);
ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area::get_reverb_uniformity);
- ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape")));
- ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape")));
- ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body")));
- ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape")));
+ ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape")));
+ ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape")));
ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape")));
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index e7b3645001..8504a18f54 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -35,11 +35,8 @@
#include "scene/main/viewport.h"
void AudioStreamPlayer3D::_mix_audio() {
- if (!stream_playback.is_valid()) {
- return;
- }
-
- if (!active) {
+ if (!stream_playback.is_valid() || !active ||
+ (stream_paused && !stream_paused_fade_out)) {
return;
}
@@ -54,8 +51,13 @@ void AudioStreamPlayer3D::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
- //mix
- if (output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) {
+ if (stream_paused_fade_out) {
+ // Short fadeout ramp
+ buffer_size = MIN(buffer_size, 128);
+ }
+
+ // Mix if we're not paused or we're fading out
+ if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
float output_pitch_scale = 0.0;
if (output_count) {
@@ -105,8 +107,10 @@ void AudioStreamPlayer3D::_mix_audio() {
int buffers = AudioServer::get_singleton()->get_channel_count();
for (int k = 0; k < buffers; k++) {
- AudioFrame vol_inc = (current.vol[k] - prev_outputs[i].vol[k]) / float(buffer_size);
- AudioFrame vol = current.vol[k];
+ AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k];
+ AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k];
+ AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
+ AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k];
AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
@@ -188,6 +192,8 @@ void AudioStreamPlayer3D::_mix_audio() {
}
output_ready = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
}
float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
@@ -237,6 +243,18 @@ void AudioStreamPlayer3D::_notification(int p_what) {
AudioServer::get_singleton()->remove_callback(_mix_audios, this);
}
+
+ if (p_what == NOTIFICATION_PAUSED) {
+ if (!can_process()) {
+ // Node can't process so we start fading out to silence
+ set_stream_paused(true);
+ }
+ }
+
+ if (p_what == NOTIFICATION_UNPAUSED) {
+ set_stream_paused(false);
+ }
+
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
@@ -552,7 +570,6 @@ void AudioStreamPlayer3D::_notification(int p_what) {
void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
- ERR_FAIL_COND(!p_stream.is_valid());
AudioServer::get_singleton()->lock();
mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
@@ -564,14 +581,15 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
setseek = -1;
}
- stream = p_stream;
- stream_playback = p_stream->instance_playback();
+ if (p_stream.is_valid()) {
+ stream = p_stream;
+ stream_playback = p_stream->instance_playback();
+ }
AudioServer::get_singleton()->unlock();
- if (stream_playback.is_null()) {
+ if (p_stream.is_valid() && stream_playback.is_null()) {
stream.unref();
- ERR_FAIL_COND(stream_playback.is_null());
}
}
@@ -608,6 +626,7 @@ float AudioStreamPlayer3D::get_max_db() const {
}
void AudioStreamPlayer3D::set_pitch_scale(float p_pitch_scale) {
+ ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
}
float AudioStreamPlayer3D::get_pitch_scale() const {
@@ -825,6 +844,20 @@ AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking()
return doppler_tracking;
}
+void AudioStreamPlayer3D::set_stream_paused(bool p_pause) {
+
+ if (p_pause != stream_paused) {
+ stream_paused = p_pause;
+ stream_paused_fade_in = stream_paused ? false : true;
+ stream_paused_fade_out = stream_paused ? true : false;
+ }
+}
+
+bool AudioStreamPlayer3D::get_stream_paused() const {
+
+ return stream_paused;
+}
+
void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
@@ -888,6 +921,9 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &AudioStreamPlayer3D::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &AudioStreamPlayer3D::get_doppler_tracking);
+ ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -898,6 +934,7 @@ void AudioStreamPlayer3D::_bind_methods() {
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::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
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");
@@ -949,9 +986,13 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
attenuation_filter_db = -24;
out_of_range_mode = OUT_OF_RANGE_MIX;
doppler_tracking = DOPPLER_TRACKING_DISABLED;
+ stream_paused = false;
+ stream_paused_fade_in = false;
+ stream_paused_fade_out = false;
velocity_tracker.instance();
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
+ set_disable_scale(true);
}
AudioStreamPlayer3D::~AudioStreamPlayer3D() {
}
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 1fcb83cf21..14413d0702 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -108,6 +108,9 @@ private:
float max_db;
float pitch_scale;
bool autoplay;
+ bool stream_paused;
+ bool stream_paused_fade_in;
+ bool stream_paused_fade_out;
StringName bus;
void _mix_audio();
@@ -199,6 +202,9 @@ public:
void set_doppler_tracking(DopplerTracking p_tracking);
DopplerTracking get_doppler_tracking() const;
+ void set_stream_paused(bool p_pause);
+ bool get_stream_paused() const;
+
AudioStreamPlayer3D();
~AudioStreamPlayer3D();
};
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 204aaef7ec..2cb59c871c 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -374,9 +374,6 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
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);
@@ -811,4 +808,5 @@ BakedLightmap::BakedLightmap() {
propagation = 1;
hdr = false;
image_path = ".";
+ set_disable_scale(true);
}
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index e11e8abe5b..a4582b7d7d 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -31,9 +31,10 @@
#include "camera.h"
#include "camera_matrix.h"
+#include "collision_object.h"
+#include "engine.h"
#include "scene/resources/material.h"
#include "scene/resources/surface_tool.h"
-
void Camera::_update_audio_listener_state() {
}
@@ -74,10 +75,7 @@ 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;
- VisualServer::get_singleton()->camera_set_transform(camera, tr);
+ VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
// here goes listener stuff
/*
@@ -143,7 +141,10 @@ void Camera::_notification(int p_what) {
Transform Camera::get_camera_transform() const {
- return get_global_transform().orthonormalized();
+ Transform tr = get_global_transform().orthonormalized();
+ tr.origin += tr.basis.get_axis(1) * v_offset;
+ tr.origin += tr.basis.get_axis(0) * h_offset;
+ return tr;
}
void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
@@ -313,6 +314,32 @@ bool Camera::is_position_behind(const Vector3 &p_pos) const {
return eyedir.dot(p_pos) < (eyedir.dot(t.origin) + near);
}
+Vector<Vector3> Camera::get_near_plane_points() const {
+ if (!is_inside_tree()) {
+ ERR_EXPLAIN("Camera is not inside scene.");
+ ERR_FAIL_COND_V(!is_inside_tree(), Vector<Vector3>());
+ }
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm;
+
+ if (mode == PROJECTION_ORTHOGONAL)
+ cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ else
+ cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+
+ Vector3 endpoints[8];
+ cm.get_endpoints(Transform(), endpoints);
+
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ for (int i = 0; i < 4; i++) {
+ points.push_back(endpoints[i + 4]);
+ }
+ return points;
+}
+
Point2 Camera::unproject_position(const Vector3 &p_pos) const {
if (!is_inside_tree()) {
@@ -468,6 +495,10 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode);
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
+
+ ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit);
+
//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");
@@ -480,7 +511,7 @@ void Camera::_bind_methods() {
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, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,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);
@@ -550,6 +581,20 @@ uint32_t Camera::get_cull_mask() const {
return layers;
}
+void Camera::set_cull_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_cull_mask(layers | (1 << p_layer));
+ } else {
+ set_cull_mask(layers & (~(1 << p_layer)));
+ }
+}
+
+bool Camera::get_cull_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (layers & (1 << p_layer));
+}
+
Vector<Plane> Camera::get_frustum() const {
ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>());
@@ -613,9 +658,231 @@ Camera::Camera() {
velocity_tracker.instance();
doppler_tracking = DOPPLER_TRACKING_DISABLED;
set_notify_transform(true);
+ set_disable_scale(true);
}
Camera::~Camera() {
VisualServer::get_singleton()->free(camera);
}
+
+////////////////////////////////////////
+
+void ClippedCamera::set_margin(float p_margin) {
+ margin = p_margin;
+}
+float ClippedCamera::get_margin() const {
+ return margin;
+}
+void ClippedCamera::set_process_mode(ProcessMode p_mode) {
+
+ if (process_mode == p_mode) {
+ return;
+ }
+ set_process_internal(p_mode == CLIP_PROCESS_IDLE);
+ set_physics_process_internal(p_mode == CLIP_PROCESS_PHYSICS);
+}
+ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
+ return process_mode;
+}
+
+Transform ClippedCamera::get_camera_transform() const {
+
+ Transform t = Camera::get_camera_transform();
+ t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
+ return t;
+}
+
+void ClippedCamera::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+
+ Spatial *parent = Object::cast_to<Spatial>(get_parent());
+ if (!parent) {
+ return;
+ }
+
+ PhysicsDirectSpaceState *dspace = get_world()->get_direct_space_state();
+ ERR_FAIL_COND(!dspace); // most likely physics set to threads
+
+ Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
+ Vector3 cam_pos = get_global_transform().origin;
+ Vector3 parent_pos = parent->get_global_transform().origin;
+
+ Plane parent_plane(parent_pos, cam_fw);
+
+ if (parent_plane.is_point_over(cam_pos)) {
+ //cam is beyond parent plane
+ return;
+ }
+
+ Vector3 ray_from = parent_plane.project(cam_pos);
+
+ clip_offset = 0; //reset by defau;t
+
+ { //check if points changed
+ Vector<Vector3> local_points = get_near_plane_points();
+
+ bool all_equal = true;
+
+ for (int i = 0; i < 5; i++) {
+ if (points[i] != local_points[i]) {
+ all_equal = false;
+ break;
+ }
+ }
+
+ if (!all_equal) {
+ PhysicsServer::get_singleton()->shape_set_data(pyramid_shape, local_points);
+ points = local_points;
+ }
+ }
+
+ Transform xf = get_global_transform();
+ xf.origin = ray_from;
+ xf.orthonormalize();
+
+ float csafe, cunsafe;
+ if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
+ clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from).normalized() * csafe);
+ }
+
+ _update_camera();
+ }
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ update_gizmo();
+ }
+}
+
+void ClippedCamera::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask = p_mask;
+}
+
+uint32_t ClippedCamera::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void ClippedCamera::set_collision_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask |= 1 << p_bit;
+ else
+ mask &= ~(1 << p_bit);
+ set_collision_mask(mask);
+}
+
+bool ClippedCamera::get_collision_mask_bit(int p_bit) const {
+
+ return get_collision_mask() & (1 << p_bit);
+}
+
+void ClippedCamera::add_exception_rid(const RID &p_rid) {
+
+ exclude.insert(p_rid);
+}
+
+void ClippedCamera::add_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
+ if (!co)
+ return;
+ add_exception_rid(co->get_rid());
+}
+
+void ClippedCamera::remove_exception_rid(const RID &p_rid) {
+
+ exclude.erase(p_rid);
+}
+
+void ClippedCamera::remove_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
+ if (!co)
+ return;
+ remove_exception_rid(co->get_rid());
+}
+
+void ClippedCamera::clear_exceptions() {
+
+ exclude.clear();
+}
+
+void ClippedCamera::set_clip_to_areas(bool p_clip) {
+
+ clip_to_areas = p_clip;
+}
+
+bool ClippedCamera::is_clip_to_areas_enabled() const {
+
+ return clip_to_areas;
+}
+
+void ClippedCamera::set_clip_to_bodies(bool p_clip) {
+
+ clip_to_bodies = p_clip;
+}
+
+bool ClippedCamera::is_clip_to_bodies_enabled() const {
+
+ return clip_to_bodies;
+}
+
+void ClippedCamera::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera::get_margin);
+
+ ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera::set_process_mode);
+ ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera::get_process_mode);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera::add_exception_rid);
+ ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera::add_exception);
+
+ ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera::remove_exception_rid);
+ ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera::remove_exception);
+
+ ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas);
+ ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies);
+ ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled);
+
+ ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera::clear_exceptions);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Clip To", "clip_to");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
+
+ BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
+ BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
+}
+ClippedCamera::ClippedCamera() {
+ margin = 0;
+ clip_offset = 0;
+ process_mode = CLIP_PROCESS_PHYSICS;
+ set_physics_process_internal(true);
+ collision_mask = 1;
+ set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
+ points.resize(5);
+ pyramid_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON);
+ clip_to_areas = false;
+ clip_to_bodies = true;
+}
+ClippedCamera::~ClippedCamera() {
+ PhysicsServer::get_singleton()->free(pyramid_shape);
+}
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 1b506e0c4f..a35c9d6e7f 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -139,9 +139,14 @@ public:
bool is_position_behind(const Vector3 &p_pos) const;
virtual Vector3 project_position(const Point2 &p_point) const;
+ Vector<Vector3> get_near_plane_points() const;
+
void set_cull_mask(uint32_t p_layers);
uint32_t get_cull_mask() const;
+ void set_cull_mask_bit(int p_layer, bool p_enable);
+ bool get_cull_mask_bit(int p_layer) const;
+
virtual Vector<Plane> get_frustum() const;
void set_environment(const Ref<Environment> &p_environment);
@@ -169,4 +174,62 @@ VARIANT_ENUM_CAST(Camera::Projection);
VARIANT_ENUM_CAST(Camera::KeepAspect);
VARIANT_ENUM_CAST(Camera::DopplerTracking);
+class ClippedCamera : public Camera {
+
+ GDCLASS(ClippedCamera, Camera);
+
+public:
+ enum ProcessMode {
+ CLIP_PROCESS_PHYSICS,
+ CLIP_PROCESS_IDLE,
+ };
+
+private:
+ ProcessMode process_mode;
+ RID pyramid_shape;
+ float margin;
+ float clip_offset;
+ uint32_t collision_mask;
+ bool clip_to_areas;
+ bool clip_to_bodies;
+
+ Set<RID> exclude;
+
+ Vector<Vector3> points;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ virtual Transform get_camera_transform() const;
+
+public:
+ void set_clip_to_areas(bool p_clip);
+ bool is_clip_to_areas_enabled() const;
+
+ void set_clip_to_bodies(bool p_clip);
+ bool is_clip_to_bodies_enabled() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_process_mode(ProcessMode p_mode);
+ ProcessMode get_process_mode() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
+ void add_exception_rid(const RID &p_rid);
+ void add_exception(const Object *p_object);
+ void remove_exception_rid(const RID &p_rid);
+ void remove_exception(const Object *p_object);
+ void clear_exceptions();
+
+ ClippedCamera();
+ ~ClippedCamera();
+};
+
+VARIANT_ENUM_CAST(ClippedCamera::ProcessMode);
#endif
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index 1d5d1b2afe..99b8ce0567 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -148,7 +148,7 @@ void CollisionObject::_bind_methods() {
BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
- ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
+ ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
@@ -305,7 +305,7 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
for (int i = 0; i < E->get().shapes.size(); i++) {
if (E->get().shapes[i].index > index_to_remove) {
- E->get().shapes[i].index -= 1;
+ E->get().shapes.write[i].index -= 1;
}
}
}
diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h
index f31d65e411..f8ef04b78f 100644
--- a/scene/3d/collision_object.h
+++ b/scene/3d/collision_object.h
@@ -39,6 +39,7 @@ class CollisionObject : public Spatial {
GDCLASS(CollisionObject, Spatial);
bool area;
+
RID rid;
struct ShapeData {
diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h
index c9c91a5824..6ca8e80ea1 100644
--- a/scene/3d/collision_shape.h
+++ b/scene/3d/collision_shape.h
@@ -49,6 +49,7 @@ class CollisionShape : public Spatial {
void resource_changed(RES res);
bool disabled;
+protected:
void _create_debug_shape();
void _update_in_shape_owner(bool p_xform_only = false);
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
new file mode 100644
index 0000000000..712f0ba78b
--- /dev/null
+++ b/scene/3d/cpu_particles.cpp
@@ -0,0 +1,1444 @@
+/*************************************************************************/
+/* cpu_particles.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 "cpu_particles.h"
+
+#include "scene/3d/camera.h"
+#include "scene/3d/particles.h"
+#include "scene/resources/particles_material.h"
+#include "servers/visual_server.h"
+
+AABB CPUParticles::get_aabb() const {
+
+ return AABB();
+}
+PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
+
+ return PoolVector<Face3>();
+}
+
+void CPUParticles::set_emitting(bool p_emitting) {
+
+ emitting = p_emitting;
+ if (!is_processing_internal()) {
+ set_process_internal(true);
+ if (is_inside_tree()) {
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ }
+ }
+}
+
+void CPUParticles::set_amount(int p_amount) {
+
+ ERR_FAIL_COND(p_amount < 1);
+
+ particles.resize(p_amount);
+ {
+ PoolVector<Particle>::Write w = particles.write();
+
+ for (int i = 0; i < p_amount; i++) {
+ w[i].active = false;
+ }
+ }
+
+ particle_data.resize((12 + 4 + 1) * p_amount);
+ VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_8BIT, VS::MULTIMESH_CUSTOM_DATA_FLOAT);
+
+ particle_order.resize(p_amount);
+}
+void CPUParticles::set_lifetime(float p_lifetime) {
+
+ ERR_FAIL_COND(p_lifetime <= 0);
+ lifetime = p_lifetime;
+}
+
+void CPUParticles::set_one_shot(bool p_one_shot) {
+
+ one_shot = p_one_shot;
+}
+
+void CPUParticles::set_pre_process_time(float p_time) {
+
+ pre_process_time = p_time;
+}
+void CPUParticles::set_explosiveness_ratio(float p_ratio) {
+
+ explosiveness_ratio = p_ratio;
+}
+void CPUParticles::set_randomness_ratio(float p_ratio) {
+
+ randomness_ratio = p_ratio;
+}
+void CPUParticles::set_use_local_coordinates(bool p_enable) {
+
+ local_coords = p_enable;
+}
+void CPUParticles::set_speed_scale(float p_scale) {
+
+ speed_scale = p_scale;
+}
+
+bool CPUParticles::is_emitting() const {
+
+ return emitting;
+}
+int CPUParticles::get_amount() const {
+
+ return particles.size();
+}
+float CPUParticles::get_lifetime() const {
+
+ return lifetime;
+}
+bool CPUParticles::get_one_shot() const {
+
+ return one_shot;
+}
+
+float CPUParticles::get_pre_process_time() const {
+
+ return pre_process_time;
+}
+float CPUParticles::get_explosiveness_ratio() const {
+
+ return explosiveness_ratio;
+}
+float CPUParticles::get_randomness_ratio() const {
+
+ return randomness_ratio;
+}
+
+bool CPUParticles::get_use_local_coordinates() const {
+
+ return local_coords;
+}
+
+float CPUParticles::get_speed_scale() const {
+
+ return speed_scale;
+}
+
+void CPUParticles::set_draw_order(DrawOrder p_order) {
+
+ draw_order = p_order;
+}
+
+CPUParticles::DrawOrder CPUParticles::get_draw_order() const {
+
+ return draw_order;
+}
+
+void CPUParticles::set_mesh(const Ref<Mesh> &p_mesh) {
+
+ mesh = p_mesh;
+ if (mesh.is_valid()) {
+ VS::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid());
+ } else {
+ VS::get_singleton()->multimesh_set_mesh(multimesh, RID());
+ }
+}
+
+Ref<Mesh> CPUParticles::get_mesh() const {
+
+ return mesh;
+}
+
+void CPUParticles::set_fixed_fps(int p_count) {
+ fixed_fps = p_count;
+}
+
+int CPUParticles::get_fixed_fps() const {
+ return fixed_fps;
+}
+
+void CPUParticles::set_fractional_delta(bool p_enable) {
+ fractional_delta = p_enable;
+}
+
+bool CPUParticles::get_fractional_delta() const {
+ return fractional_delta;
+}
+
+String CPUParticles::get_configuration_warning() const {
+
+ String warnings;
+
+ return warnings;
+}
+
+void CPUParticles::restart() {
+
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+
+ {
+ int pc = particles.size();
+ PoolVector<Particle>::Write w = particles.write();
+
+ for (int i = 0; i < pc; i++) {
+ w[i].active = false;
+ }
+ }
+}
+
+void CPUParticles::set_spread(float p_spread) {
+
+ spread = p_spread;
+}
+
+float CPUParticles::get_spread() const {
+
+ return spread;
+}
+
+void CPUParticles::set_flatness(float p_flatness) {
+
+ flatness = p_flatness;
+}
+float CPUParticles::get_flatness() const {
+
+ return flatness;
+}
+
+void CPUParticles::set_param(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ parameters[p_param] = p_value;
+}
+float CPUParticles::get_param(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return parameters[p_param];
+}
+
+void CPUParticles::set_param_randomness(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ randomness[p_param] = p_value;
+}
+float CPUParticles::get_param_randomness(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return randomness[p_param];
+}
+
+static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) {
+
+ Ref<Curve> curve = p_curve;
+ if (!curve.is_valid())
+ return;
+
+ curve->ensure_default_setup(p_min, p_max);
+}
+
+void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ curve_parameters[p_param] = p_curve;
+
+ switch (p_param) {
+ case PARAM_INITIAL_LINEAR_VELOCITY: {
+ //do none for this one
+ } break;
+ case PARAM_ANGULAR_VELOCITY: {
+ _adjust_curve_range(p_curve, -360, 360);
+ } break;
+ /*case PARAM_ORBIT_VELOCITY: {
+ _adjust_curve_range(p_curve, -500, 500);
+ } break;*/
+ case PARAM_LINEAR_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_RADIAL_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_TANGENTIAL_ACCEL: {
+ _adjust_curve_range(p_curve, -200, 200);
+ } break;
+ case PARAM_DAMPING: {
+ _adjust_curve_range(p_curve, 0, 100);
+ } break;
+ case PARAM_ANGLE: {
+ _adjust_curve_range(p_curve, -360, 360);
+ } break;
+ case PARAM_SCALE: {
+
+ } break;
+ case PARAM_HUE_VARIATION: {
+ _adjust_curve_range(p_curve, -1, 1);
+ } break;
+ case PARAM_ANIM_SPEED: {
+ _adjust_curve_range(p_curve, 0, 200);
+ } break;
+ case PARAM_ANIM_OFFSET: {
+ } break;
+ default: {}
+ }
+}
+Ref<Curve> CPUParticles::get_param_curve(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>());
+
+ return curve_parameters[p_param];
+}
+
+void CPUParticles::set_color(const Color &p_color) {
+
+ color = p_color;
+}
+
+Color CPUParticles::get_color() const {
+
+ return color;
+}
+
+void CPUParticles::set_color_ramp(const Ref<Gradient> &p_ramp) {
+
+ color_ramp = p_ramp;
+}
+
+Ref<Gradient> CPUParticles::get_color_ramp() const {
+
+ return color_ramp;
+}
+
+void CPUParticles::set_particle_flag(Flags p_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ flags[p_flag] = p_enable;
+ if (p_flag == FLAG_DISABLE_Z) {
+ _change_notify();
+ }
+}
+
+bool CPUParticles::get_particle_flag(Flags p_flag) const {
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags[p_flag];
+}
+
+void CPUParticles::set_emission_shape(EmissionShape p_shape) {
+
+ emission_shape = p_shape;
+}
+
+void CPUParticles::set_emission_sphere_radius(float p_radius) {
+
+ emission_sphere_radius = p_radius;
+}
+
+void CPUParticles::set_emission_box_extents(Vector3 p_extents) {
+
+ emission_box_extents = p_extents;
+}
+
+void CPUParticles::set_emission_points(const PoolVector<Vector3> &p_points) {
+
+ emission_points = p_points;
+}
+
+void CPUParticles::set_emission_normals(const PoolVector<Vector3> &p_normals) {
+
+ emission_normals = p_normals;
+}
+
+void CPUParticles::set_emission_colors(const PoolVector<Color> &p_colors) {
+
+ emission_colors = p_colors;
+}
+
+float CPUParticles::get_emission_sphere_radius() const {
+
+ return emission_sphere_radius;
+}
+Vector3 CPUParticles::get_emission_box_extents() const {
+
+ return emission_box_extents;
+}
+PoolVector<Vector3> CPUParticles::get_emission_points() const {
+
+ return emission_points;
+}
+PoolVector<Vector3> CPUParticles::get_emission_normals() const {
+
+ return emission_normals;
+}
+
+PoolVector<Color> CPUParticles::get_emission_colors() const {
+
+ return emission_colors;
+}
+
+CPUParticles::EmissionShape CPUParticles::get_emission_shape() const {
+ return emission_shape;
+}
+void CPUParticles::set_gravity(const Vector3 &p_gravity) {
+
+ gravity = p_gravity;
+}
+
+Vector3 CPUParticles::get_gravity() const {
+
+ return gravity;
+}
+
+void CPUParticles::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "color" && color_ramp.is_valid()) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ property.usage = 0;
+ }
+
+ if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ property.usage = 0;
+ }
+ /*
+ if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ property.usage = 0;
+ }
+ */
+}
+
+static uint32_t idhash(uint32_t x) {
+
+ x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
+ x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b);
+ x = (x >> uint32_t(16)) ^ x;
+ return x;
+}
+
+static float rand_from_seed(uint32_t &seed) {
+ int k;
+ int s = int(seed);
+ if (s == 0)
+ s = 305420679;
+ k = s / 127773;
+ s = 16807 * (s - k * 127773) - 2836 * k;
+ if (s < 0)
+ s += 2147483647;
+ seed = uint32_t(s);
+ return float(seed % uint32_t(65536)) / 65535.0;
+}
+
+static float rand_from_seed_m1_p1(uint32_t &seed) {
+ return rand_from_seed(seed) * 2.0 - 1.0;
+}
+
+void CPUParticles::_particles_process(float p_delta) {
+
+ p_delta *= speed_scale;
+
+ int pcount = particles.size();
+ PoolVector<Particle>::Write w = particles.write();
+
+ Particle *parray = w.ptr();
+
+ float prev_time = time;
+ time += p_delta;
+ if (time > lifetime) {
+ time = Math::fmod(time, lifetime);
+ cycle++;
+ if (one_shot && cycle > 0) {
+ emitting = false;
+ }
+ }
+
+ Transform emission_xform;
+ Basis velocity_xform;
+ if (!local_coords) {
+ emission_xform = get_global_transform();
+ velocity_xform = emission_xform.basis.inverse().transposed();
+ }
+
+ for (int i = 0; i < pcount; i++) {
+
+ Particle &p = parray[i];
+
+ if (!emitting && !p.active)
+ continue;
+
+ float restart_time = (float(i) / float(pcount)) * lifetime;
+ float local_delta = p_delta;
+
+ if (randomness_ratio > 0.0) {
+ uint32_t seed = cycle;
+ if (restart_time >= time) {
+ seed -= uint32_t(1);
+ }
+ seed *= uint32_t(pcount);
+ seed += uint32_t(i);
+ float random = float(idhash(seed) % uint32_t(65536)) / 65536.0;
+ restart_time += randomness_ratio * random * 1.0 / float(pcount);
+ }
+
+ restart_time *= (1.0 - explosiveness_ratio);
+ bool restart = false;
+
+ if (time > prev_time) {
+ // restart_time >= prev_time is used so particles emit in the first frame they are processed
+
+ if (restart_time >= prev_time && restart_time < time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = (time - restart_time) * lifetime;
+ }
+ }
+
+ } else if (local_delta > 0.0) {
+ if (restart_time >= prev_time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = (1.0 - restart_time + time) * lifetime;
+ }
+
+ } else if (restart_time < time) {
+ restart = true;
+ if (fractional_delta) {
+ local_delta = (time - restart_time) * lifetime;
+ }
+ }
+ }
+
+ if (restart) {
+
+ if (!emitting) {
+ p.active = false;
+ continue;
+ }
+ p.active = true;
+
+ /*float tex_linear_velocity = 0;
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
+ }*/
+
+ float tex_angle = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0);
+ }
+
+ float tex_anim_offset = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0);
+ }
+
+ p.seed = Math::rand();
+
+ p.angle_rand = Math::randf();
+ p.scale_rand = Math::randf();
+ p.hue_rot_rand = Math::randf();
+ p.anim_offset_rand = Math::randf();
+
+ float angle1_rad;
+ float angle2_rad;
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
+ Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
+ p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+
+ } else {
+ //initiate velocity spread in 3D
+ angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0;
+ angle2_rad = (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0;
+
+ Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad));
+ Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad));
+ direction_yz.z = direction_yz.z / Math::sqrt(direction_yz.z); //better uniform distribution
+ Vector3 direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
+ direction.normalize();
+ p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ }
+
+ float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[1] = 0.0; //phase
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
+ p.transform = Transform();
+ p.time = 0;
+ p.base_color = Color(1, 1, 1, 1);
+
+ switch (emission_shape) {
+ case EMISSION_SHAPE_POINT: {
+ //do none
+ } break;
+ case EMISSION_SHAPE_SPHERE: {
+ p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius;
+ } break;
+ case EMISSION_SHAPE_BOX: {
+ p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_box_extents;
+ } break;
+ case EMISSION_SHAPE_POINTS:
+ case EMISSION_SHAPE_DIRECTED_POINTS: {
+
+ int pc = emission_points.size();
+ if (pc == 0)
+ break;
+
+ int random_idx = Math::rand() % pc;
+
+ p.transform.origin = emission_points.get(random_idx);
+
+ if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
+ if (flags[FLAG_DISABLE_Z]) {
+ /*
+ mat2 rotm;
+ ";
+ rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;
+ rotm[1] = rotm[0].yx * vec2(1.0, -1.0);
+ VELOCITY.xy = rotm * VELOCITY.xy;
+ */
+ } else {
+ Vector3 normal = emission_normals.get(random_idx);
+ Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0);
+ Vector3 tangent = v0.cross(normal).normalized();
+ Vector3 bitangent = tangent.cross(normal).normalized();
+ Basis m3;
+ m3.set_axis(0, tangent);
+ m3.set_axis(1, bitangent);
+ m3.set_axis(2, normal);
+ p.velocity = m3.xform(p.velocity);
+ }
+ }
+
+ if (emission_colors.size() == pc) {
+ p.base_color = emission_colors.get(random_idx);
+ }
+ } break;
+ }
+
+ if (!local_coords) {
+ p.velocity = velocity_xform.xform(p.velocity);
+ p.transform = emission_xform * p.transform;
+ }
+
+ if (flags[FLAG_DISABLE_Z]) {
+ p.velocity.z = 0.0;
+ p.velocity.z = 0.0;
+ }
+
+ } else if (!p.active) {
+ continue;
+ } else {
+
+ uint32_t alt_seed = p.seed;
+
+ p.time += local_delta;
+ p.custom[1] = p.time / lifetime;
+
+ float tex_linear_velocity = 0.0;
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]);
+ }
+ /*
+ float tex_orbit_velocity = 0.0;
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) {
+ tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]);
+ }
+ }
+*/
+ float tex_angular_velocity = 0.0;
+ if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
+ tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]);
+ }
+
+ float tex_linear_accel = 0.0;
+ if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
+ tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_tangential_accel = 0.0;
+ if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
+ tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_radial_accel = 0.0;
+ if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
+ tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]);
+ }
+
+ float tex_damping = 0.0;
+ if (curve_parameters[PARAM_DAMPING].is_valid()) {
+ tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]);
+ }
+
+ float tex_angle = 0.0;
+ if (curve_parameters[PARAM_ANGLE].is_valid()) {
+ tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]);
+ }
+ float tex_anim_speed = 0.0;
+ if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
+ tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]);
+ }
+
+ float tex_anim_offset = 0.0;
+ if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
+ tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]);
+ }
+
+ Vector3 force = gravity;
+ Vector3 pos = p.transform.origin;
+ if (flags[FLAG_DISABLE_Z]) {
+ pos.z = 0.0;
+ }
+ //apply linear acceleration
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3();
+ //apply radial acceleration
+ Vector3 org = emission_xform.origin;
+ Vector3 diff = pos - org;
+ force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3();
+ //apply tangential acceleration;
+ if (flags[FLAG_DISABLE_Z]) {
+
+ Vector3 yx = Vector3(diff.y, 0, diff.x);
+ force += yx.length() > 0.0 ? (yx * Vector3(-1.0, 0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+
+ } else {
+ Vector3 crossDiff = diff.normalized().cross(gravity.normalized());
+ force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+ }
+ //apply attractor forces
+ p.velocity += force * local_delta;
+ //orbit velocity
+#if 0
+ if (flags[FLAG_DISABLE_Z]) {
+
+ float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);
+ if (orbit_amount != 0.0) {
+ float ang = orbit_amount * DELTA * pi * 2.0;
+ mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));
+ TRANSFORM[3].xy -= diff.xy;
+ TRANSFORM[3].xy += rot * diff.xy;
+ }
+ }
+#endif
+ if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ p.velocity = p.velocity.normalized() * tex_linear_velocity;
+ }
+ if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
+
+ float v = p.velocity.length();
+ float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ v -= damp * local_delta;
+ if (v < 0.0) {
+ p.velocity = Vector3();
+ } else {
+ p.velocity = p.velocity.normalized() * v;
+ }
+ }
+ float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
+ if (flags[FLAG_ANIM_LOOP]) {
+ p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop
+
+ } else {
+ p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only
+ }
+ }
+ //apply color
+ //apply hue rotation
+
+ float tex_scale = 1.0;
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]);
+ }
+
+ float tex_hue_variation = 0.0;
+ if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
+ tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]);
+ }
+
+ float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ float hue_rot_c = Math::cos(hue_rot_angle);
+ float hue_rot_s = Math::sin(hue_rot_angle);
+
+ Basis hue_rot_mat;
+ {
+ Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114);
+ Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886);
+ Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203);
+
+ for (int j = 0; j < 3; j++) {
+ hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s;
+ }
+ }
+
+ if (color_ramp.is_valid()) {
+ p.color = color_ramp->get_color_at_offset(p.custom[1]) * color;
+ } else {
+ p.color = color;
+ }
+
+ Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b));
+ p.color.r = color_rgb.x;
+ p.color.g = color_rgb.y;
+ p.color.b = color_rgb.z;
+
+ p.color *= p.base_color;
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (p.velocity.length() > 0.0) {
+ p.transform.basis.set_axis(1, p.velocity.normalized());
+ } else {
+ p.transform.basis.set_axis(1, p.transform.basis.get_axis(1));
+ }
+ p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
+ p.transform.basis.set_axis(2, Vector3(0, 0, 1));
+
+ } else {
+ p.transform.basis.set_axis(0, Vector3(Math::cos(p.custom[0]), -Math::sin(p.custom[0]), 0.0));
+ p.transform.basis.set_axis(1, Vector3(Math::sin(p.custom[0]), Math::cos(p.custom[0]), 0.0));
+ p.transform.basis.set_axis(2, Vector3(0, 0, 1));
+ }
+
+ } else {
+ //orient particle Y towards velocity
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ if (p.velocity.length() > 0.0) {
+ p.transform.basis.set_axis(1, p.velocity.normalized());
+ } else {
+ p.transform.basis.set_axis(1, p.transform.basis.get_axis(1).normalized());
+ }
+ if (p.transform.basis.get_axis(1) == p.transform.basis.get_axis(0)) {
+ p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
+ p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized());
+ } else {
+ p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized());
+ p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized());
+ }
+ } else {
+ p.transform.basis.orthonormalize();
+ }
+
+ //turn particle by rotation in Y
+ if (flags[FLAG_ROTATE_Y]) {
+ Basis rot_y(Vector3(0, 1, 0), p.custom[0]);
+ p.transform.basis = p.transform.basis * rot_y;
+ }
+ }
+
+ //scale by scale
+ float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ if (base_scale == 0.0) base_scale = 0.000001;
+
+ p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
+
+ if (flags[FLAG_DISABLE_Z]) {
+ p.velocity.z = 0.0;
+ p.transform.origin.z = 0.0;
+ }
+
+ p.transform.origin += p.velocity * local_delta;
+ }
+}
+
+void CPUParticles::_update_particle_data_buffer() {
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+
+ {
+
+ int pc = particles.size();
+
+ PoolVector<int>::Write ow;
+ int *order = NULL;
+
+ PoolVector<float>::Write w = particle_data.write();
+ PoolVector<Particle>::Read r = particles.read();
+ float *ptr = w.ptr();
+
+ Transform un_transform;
+ if (!local_coords) {
+ un_transform = get_global_transform().affine_inverse();
+ }
+
+ if (draw_order != DRAW_ORDER_INDEX) {
+ ow = particle_order.write();
+ order = ow.ptr();
+
+ for (int i = 0; i < pc; i++) {
+ order[i] = i;
+ }
+ if (draw_order == DRAW_ORDER_LIFETIME) {
+ SortArray<int, SortLifetime> sorter;
+ sorter.compare.particles = r.ptr();
+ sorter.sort(order, pc);
+ } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) {
+ Camera *c = get_viewport()->get_camera();
+ if (c) {
+ Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close
+
+ if (local_coords) {
+ dir = un_transform.basis.xform(dir).normalized();
+ }
+
+ SortArray<int, SortAxis> sorter;
+ sorter.compare.particles = r.ptr();
+ sorter.compare.axis = dir;
+ sorter.sort(order, pc);
+ }
+ }
+ }
+
+ for (int i = 0; i < pc; i++) {
+
+ int idx = order ? order[i] : i;
+
+ Transform t = r[idx].transform;
+
+ if (!local_coords) {
+ t = un_transform * t;
+ }
+
+ if (r[idx].active) {
+ ptr[0] = t.basis.elements[0][0];
+ ptr[1] = t.basis.elements[0][1];
+ ptr[2] = t.basis.elements[0][2];
+ ptr[3] = t.origin.x;
+ ptr[4] = t.basis.elements[1][0];
+ ptr[5] = t.basis.elements[1][1];
+ ptr[6] = t.basis.elements[1][2];
+ ptr[7] = t.origin.y;
+ ptr[8] = t.basis.elements[2][0];
+ ptr[9] = t.basis.elements[2][1];
+ ptr[10] = t.basis.elements[2][2];
+ ptr[11] = t.origin.z;
+ } else {
+ zeromem(ptr, sizeof(float) * 12);
+ }
+
+ Color c = r[idx].color;
+ uint8_t *data8 = (uint8_t *)&ptr[12];
+ data8[0] = CLAMP(c.r * 255.0, 0, 255);
+ data8[1] = CLAMP(c.g * 255.0, 0, 255);
+ data8[2] = CLAMP(c.b * 255.0, 0, 255);
+ data8[3] = CLAMP(c.a * 255.0, 0, 255);
+
+ ptr[13] = r[idx].custom[0];
+ ptr[14] = r[idx].custom[1];
+ ptr[15] = r[idx].custom[2];
+ ptr[16] = r[idx].custom[3];
+
+ ptr += 17;
+ }
+ }
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+}
+
+void CPUParticles::_update_render_thread() {
+
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+
+ VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+}
+
+void CPUParticles::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (is_processing_internal()) {
+
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ if (is_processing_internal()) {
+
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ }
+ }
+
+ if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
+ }
+
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+
+ if (particles.size() == 0)
+ return;
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
+
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ }
+
+ _update_particle_data_buffer();
+ }
+}
+
+void CPUParticles::convert_from_particles(Node *p_particles) {
+
+ Particles *particles = Object::cast_to<Particles>(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ set_emitting(particles->is_emitting());
+ set_amount(particles->get_amount());
+ set_lifetime(particles->get_lifetime());
+ set_one_shot(particles->get_one_shot());
+ set_pre_process_time(particles->get_pre_process_time());
+ set_explosiveness_ratio(particles->get_explosiveness_ratio());
+ set_randomness_ratio(particles->get_randomness_ratio());
+ set_use_local_coordinates(particles->get_use_local_coordinates());
+ set_fixed_fps(particles->get_fixed_fps());
+ set_fractional_delta(particles->get_fractional_delta());
+ set_speed_scale(particles->get_speed_scale());
+ set_draw_order(DrawOrder(particles->get_draw_order()));
+ set_mesh(particles->get_draw_pass_mesh(0));
+
+ Ref<ParticlesMaterial> material = particles->get_process_material();
+ if (material.is_null())
+ return;
+
+ set_spread(material->get_spread());
+ set_flatness(material->get_flatness());
+
+ set_color(material->get_color());
+
+ Ref<GradientTexture> gt = material->get_color_ramp();
+ if (gt.is_valid()) {
+ set_color_ramp(gt->get_gradient());
+ }
+
+ set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
+ set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
+ set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP));
+
+ set_emission_shape(EmissionShape(material->get_emission_shape()));
+ set_emission_sphere_radius(material->get_emission_sphere_radius());
+ set_emission_box_extents(material->get_emission_box_extents());
+
+ set_gravity(material->get_gravity());
+
+#define CONVERT_PARAM(m_param) \
+ set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ { \
+ Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
+ if (ctex.is_valid()) set_param_curve(m_param, ctex->get_curve()); \
+ } \
+ set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+
+ CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
+ CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
+ // CONVERT_PARAM(PARAM_ORBIT_VELOCITY);
+ CONVERT_PARAM(PARAM_LINEAR_ACCEL);
+ CONVERT_PARAM(PARAM_RADIAL_ACCEL);
+ CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL);
+ CONVERT_PARAM(PARAM_DAMPING);
+ CONVERT_PARAM(PARAM_ANGLE);
+ CONVERT_PARAM(PARAM_SCALE);
+ CONVERT_PARAM(PARAM_HUE_VARIATION);
+ CONVERT_PARAM(PARAM_ANIM_SPEED);
+ CONVERT_PARAM(PARAM_ANIM_OFFSET);
+
+#undef CONVERT_PARAM
+}
+
+void CPUParticles::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles::set_emitting);
+ ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles::set_amount);
+ ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles::set_one_shot);
+ ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles::set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles::set_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles::set_fixed_fps);
+ ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles::set_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles::is_emitting);
+ ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles::get_amount);
+ ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles::get_lifetime);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles::get_one_shot);
+ ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles::get_pre_process_time);
+ ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles::get_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles::get_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles::get_fixed_fps);
+ ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles::set_draw_order);
+
+ ClassDB::bind_method(D_METHOD("get_draw_order"), &CPUParticles::get_draw_order);
+
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CPUParticles::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles::get_mesh);
+
+ ClassDB::bind_method(D_METHOD("restart"), &CPUParticles::restart);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ 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_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_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,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");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+
+ BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
+
+ ////////////////////////////////
+
+ ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles::set_spread);
+ ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles::get_spread);
+
+ ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles::set_flatness);
+ ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles::get_flatness);
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles::get_param);
+
+ ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles::set_param_randomness);
+ ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles::get_param_randomness);
+
+ ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles::set_param_curve);
+ ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles::get_param_curve);
+
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &CPUParticles::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &CPUParticles::get_color);
+
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles::get_color_ramp);
+
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles::get_particle_flag);
+
+ ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles::get_emission_shape);
+
+ ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &CPUParticles::set_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &CPUParticles::get_emission_sphere_radius);
+
+ ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &CPUParticles::set_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &CPUParticles::get_emission_box_extents);
+
+ ClassDB::bind_method(D_METHOD("set_emission_points", "array"), &CPUParticles::set_emission_points);
+ ClassDB::bind_method(D_METHOD("get_emission_points"), &CPUParticles::get_emission_points);
+
+ ClassDB::bind_method(D_METHOD("set_emission_normals", "array"), &CPUParticles::set_emission_normals);
+ ClassDB::bind_method(D_METHOD("get_emission_normals"), &CPUParticles::get_emission_normals);
+
+ ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles::set_emission_colors);
+ ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles::get_emission_colors);
+
+ ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles::get_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles::set_gravity);
+
+ ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles::convert_from_particles);
+
+ ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles::_update_render_thread);
+
+ ADD_GROUP("Emission Shape", "emission_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
+ ADD_GROUP("Flags", "flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z);
+ ADD_GROUP("Spread", "");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
+ 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,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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
+ /*
+ ADD_GROUP("Orbit Velocity", "orbit_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
+*/
+ ADD_GROUP("Linear Accel", "linear_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
+ ADD_GROUP("Radial Accel", "radial_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
+ ADD_GROUP("Tangential Accel", "tangential_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
+ ADD_GROUP("Damping", "");
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
+ ADD_GROUP("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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
+ ADD_GROUP("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, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_GROUP("Color", "");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp");
+
+ ADD_GROUP("Hue Variation", "hue_");
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION);
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
+ ADD_GROUP("Animation", "anim_");
+ 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, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP);
+
+ BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
+ //BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGLE);
+ BIND_ENUM_CONSTANT(PARAM_SCALE);
+ BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
+}
+
+CPUParticles::CPUParticles() {
+
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+
+ multimesh = VisualServer::get_singleton()->multimesh_create();
+ set_base(multimesh);
+
+ set_emitting(true);
+ set_one_shot(false);
+ set_amount(8);
+ set_lifetime(1);
+ set_fixed_fps(0);
+ set_fractional_delta(true);
+ set_pre_process_time(0);
+ set_explosiveness_ratio(0);
+ set_randomness_ratio(0);
+ set_use_local_coordinates(true);
+
+ set_draw_order(DRAW_ORDER_INDEX);
+ set_speed_scale(1);
+
+ set_spread(45);
+ set_flatness(0);
+ set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1);
+ //set_param(PARAM_ORBIT_VELOCITY, 0);
+ set_param(PARAM_LINEAR_ACCEL, 0);
+ set_param(PARAM_RADIAL_ACCEL, 0);
+ set_param(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param(PARAM_DAMPING, 0);
+ set_param(PARAM_ANGLE, 0);
+ set_param(PARAM_SCALE, 1);
+ set_param(PARAM_HUE_VARIATION, 0);
+ set_param(PARAM_ANIM_SPEED, 0);
+ set_param(PARAM_ANIM_OFFSET, 0);
+ set_emission_shape(EMISSION_SHAPE_POINT);
+ set_emission_sphere_radius(1);
+ set_emission_box_extents(Vector3(1, 1, 1));
+
+ set_gravity(Vector3(0, -9.8, 0));
+
+ for (int i = 0; i < PARAM_MAX; i++) {
+ set_param_randomness(Parameter(i), 0);
+ }
+
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = false;
+ }
+
+ set_color(Color(1, 1, 1, 1));
+
+#ifndef NO_THREADS
+ update_mutex = Mutex::create();
+#endif
+}
+
+CPUParticles::~CPUParticles() {
+ VS::get_singleton()->free(multimesh);
+
+#ifndef NO_THREADS
+ memdelete(update_mutex);
+#endif
+}
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
new file mode 100644
index 0000000000..47d0ef3f5e
--- /dev/null
+++ b/scene/3d/cpu_particles.h
@@ -0,0 +1,287 @@
+/*************************************************************************/
+/* cpu_particles.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 CPU_PARTICLES_H
+#define CPU_PARTICLES_H
+
+#include "rid.h"
+#include "scene/3d/visual_instance.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class CPUParticles : public GeometryInstance {
+private:
+ GDCLASS(CPUParticles, GeometryInstance);
+
+public:
+ enum DrawOrder {
+ DRAW_ORDER_INDEX,
+ DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_VIEW_DEPTH,
+ };
+
+ enum Parameter {
+
+ PARAM_INITIAL_LINEAR_VELOCITY,
+ PARAM_ANGULAR_VELOCITY,
+ //PARAM_ORBIT_VELOCITY,
+ PARAM_LINEAR_ACCEL,
+ PARAM_RADIAL_ACCEL,
+ PARAM_TANGENTIAL_ACCEL,
+ PARAM_DAMPING,
+ PARAM_ANGLE,
+ PARAM_SCALE,
+ PARAM_HUE_VARIATION,
+ PARAM_ANIM_SPEED,
+ PARAM_ANIM_OFFSET,
+ PARAM_MAX
+ };
+
+ enum Flags {
+ FLAG_ALIGN_Y_TO_VELOCITY,
+ FLAG_ROTATE_Y,
+ FLAG_DISABLE_Z,
+ FLAG_ANIM_LOOP,
+ FLAG_MAX
+ };
+
+ enum EmissionShape {
+ EMISSION_SHAPE_POINT,
+ EMISSION_SHAPE_SPHERE,
+ EMISSION_SHAPE_BOX,
+ EMISSION_SHAPE_POINTS,
+ EMISSION_SHAPE_DIRECTED_POINTS,
+ };
+
+private:
+ bool emitting;
+
+ struct Particle {
+ Transform transform;
+ Color color;
+ float custom[4];
+ Vector3 velocity;
+ bool active;
+ float angle_rand;
+ float scale_rand;
+ float hue_rot_rand;
+ float anim_offset_rand;
+ float time;
+ Color base_color;
+
+ uint32_t seed;
+ };
+
+ float time;
+ float inactive_time;
+ float frame_remainder;
+ int cycle;
+
+ RID multimesh;
+
+ PoolVector<Particle> particles;
+ PoolVector<float> particle_data;
+ PoolVector<int> particle_order;
+
+ struct SortLifetime {
+ const Particle *particles;
+
+ bool operator()(int p_a, int p_b) const {
+ return particles[p_a].time < particles[p_b].time;
+ }
+ };
+
+ struct SortAxis {
+ const Particle *particles;
+ Vector3 axis;
+ bool operator()(int p_a, int p_b) const {
+
+ return axis.dot(particles[p_a].transform.origin) < axis.dot(particles[p_b].transform.origin);
+ }
+ };
+
+ //
+
+ bool one_shot;
+
+ float lifetime;
+ float pre_process_time;
+ float explosiveness_ratio;
+ float randomness_ratio;
+ float speed_scale;
+ bool local_coords;
+ int fixed_fps;
+ bool fractional_delta;
+
+ DrawOrder draw_order;
+
+ Ref<Mesh> mesh;
+
+ ////////
+
+ float spread;
+ float flatness;
+
+ float parameters[PARAM_MAX];
+ float randomness[PARAM_MAX];
+
+ Ref<Curve> curve_parameters[PARAM_MAX];
+ Color color;
+ Ref<Gradient> color_ramp;
+
+ bool flags[FLAG_MAX];
+
+ EmissionShape emission_shape;
+ float emission_sphere_radius;
+ Vector3 emission_box_extents;
+ PoolVector<Vector3> emission_points;
+ PoolVector<Vector3> emission_normals;
+ PoolVector<Color> emission_colors;
+ int emission_point_count;
+
+ bool anim_loop;
+ Vector3 gravity;
+
+ void _particles_process(float p_delta);
+ void _update_particle_data_buffer();
+
+ Mutex *update_mutex;
+
+ void _update_render_thread();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+ AABB get_aabb() const;
+ PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ void set_emitting(bool p_emitting);
+ void set_amount(int p_amount);
+ void set_lifetime(float p_lifetime);
+ void set_one_shot(bool p_one_shot);
+ void set_pre_process_time(float p_time);
+ void set_explosiveness_ratio(float p_ratio);
+ void set_randomness_ratio(float p_ratio);
+ void set_visibility_aabb(const AABB &p_aabb);
+ void set_use_local_coordinates(bool p_enable);
+ void set_speed_scale(float p_scale);
+
+ bool is_emitting() const;
+ int get_amount() const;
+ float get_lifetime() const;
+ bool get_one_shot() const;
+ float get_pre_process_time() const;
+ float get_explosiveness_ratio() const;
+ float get_randomness_ratio() const;
+ AABB get_visibility_aabb() const;
+ bool get_use_local_coordinates() const;
+ float get_speed_scale() const;
+
+ void set_fixed_fps(int p_count);
+ int get_fixed_fps() const;
+
+ void set_fractional_delta(bool p_enable);
+ bool get_fractional_delta() const;
+
+ void set_draw_order(DrawOrder p_order);
+ DrawOrder get_draw_order() const;
+
+ void set_draw_passes(int p_count);
+ int get_draw_passes() const;
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ ///////////////////
+
+ void set_spread(float p_spread);
+ float get_spread() const;
+
+ void set_flatness(float p_flatness);
+ float get_flatness() const;
+
+ void set_param(Parameter p_param, float p_value);
+ float get_param(Parameter p_param) const;
+
+ void set_param_randomness(Parameter p_param, float p_value);
+ float get_param_randomness(Parameter p_param) const;
+
+ void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
+ Ref<Curve> get_param_curve(Parameter p_param) const;
+
+ void set_color(const Color &p_color);
+ Color get_color() const;
+
+ void set_color_ramp(const Ref<Gradient> &p_texture);
+ Ref<Gradient> get_color_ramp() const;
+
+ void set_particle_flag(Flags p_flag, bool p_enable);
+ bool get_particle_flag(Flags p_flag) const;
+
+ void set_emission_shape(EmissionShape p_shape);
+ void set_emission_sphere_radius(float p_radius);
+ void set_emission_box_extents(Vector3 p_extents);
+ void set_emission_points(const PoolVector<Vector3> &p_points);
+ void set_emission_normals(const PoolVector<Vector3> &p_normals);
+ void set_emission_colors(const PoolVector<Color> &p_colors);
+ void set_emission_point_count(int p_count);
+
+ EmissionShape get_emission_shape() const;
+ float get_emission_sphere_radius() const;
+ Vector3 get_emission_box_extents() const;
+ PoolVector<Vector3> get_emission_points() const;
+ PoolVector<Vector3> get_emission_normals() const;
+ PoolVector<Color> get_emission_colors() const;
+ int get_emission_point_count() const;
+
+ void set_gravity(const Vector3 &p_gravity);
+ Vector3 get_gravity() const;
+
+ virtual String get_configuration_warning() const;
+
+ void restart();
+
+ void convert_from_particles(Node *p_particles);
+
+ CPUParticles();
+ ~CPUParticles();
+};
+
+VARIANT_ENUM_CAST(CPUParticles::DrawOrder)
+VARIANT_ENUM_CAST(CPUParticles::Parameter)
+VARIANT_ENUM_CAST(CPUParticles::Flags)
+VARIANT_ENUM_CAST(CPUParticles::EmissionShape)
+
+#endif // CPU_PARTICLES_H
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 4ad2eb60ee..6276d02eff 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -557,6 +557,7 @@ GIProbe::GIProbe() {
compress = false;
gi_probe = VS::get_singleton()->gi_probe_create();
+ set_disable_scale(true);
}
GIProbe::~GIProbe() {
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 7c42638107..16164cf3bf 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -306,6 +306,7 @@ Light::Light(VisualServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0);
set_param(PARAM_SHADOW_BIAS, 0.15);
+ set_disable_scale(true);
}
Light::Light() {
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 80bae911d4..e277cae5b7 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -36,6 +36,7 @@
#include "scene/resources/material.h"
#include "scene/scene_string_names.h"
#include "skeleton.h"
+
bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) {
//this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else.
@@ -256,7 +257,7 @@ void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_ma
ERR_FAIL_INDEX(p_surface, materials.size());
- materials[p_surface] = p_material;
+ materials.write[p_surface] = p_material;
if (materials[p_surface].is_valid())
VS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid());
@@ -371,7 +372,7 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
}
MeshInstance::MeshInstance() {
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 5d359cd4d5..0dfec538f9 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -41,6 +41,7 @@ class MeshInstance : public GeometryInstance {
GDCLASS(MeshInstance, GeometryInstance);
+protected:
Ref<Mesh> mesh;
NodePath skeleton_path;
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index 77bf703706..8d84d2408c 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -73,7 +73,7 @@ void Navigation::_navmesh_link(int p_id) {
Vector3 ep = nm.xform.xform(r[idx]);
center += ep;
e.point = _get_point(ep);
- p.edges[j] = e;
+ p.edges.write[j] = e;
if (j >= 2) {
Vector3 epa = nm.xform.xform(r[indices[j - 2]]);
@@ -118,18 +118,16 @@ void Navigation::_navmesh_link(int p_id) {
ConnectionPending pending;
pending.polygon = &p;
pending.edge = j;
- p.edges[j].P = C->get().pending.push_back(pending);
+ p.edges.write[j].P = C->get().pending.push_back(pending);
continue;
- //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
}
- //ERR_CONTINUE(C->get().B!=NULL); //wut
C->get().B = &p;
C->get().B_edge = j;
- C->get().A->edges[C->get().A_edge].C = &p;
- C->get().A->edges[C->get().A_edge].C_edge = j;
- p.edges[j].C = C->get().A;
- p.edges[j].C_edge = C->get().A_edge;
+ C->get().A->edges.write[C->get().A_edge].C = &p;
+ C->get().A->edges.write[C->get().A_edge].C_edge = j;
+ p.edges.write[j].C = C->get().A;
+ p.edges.write[j].C_edge = C->get().A_edge;
//connection successful.
}
}
@@ -165,10 +163,10 @@ void Navigation::_navmesh_unlink(int p_id) {
} else if (C->get().B) {
//disconnect
- C->get().B->edges[C->get().B_edge].C = NULL;
- C->get().B->edges[C->get().B_edge].C_edge = -1;
- C->get().A->edges[C->get().A_edge].C = NULL;
- C->get().A->edges[C->get().A_edge].C_edge = -1;
+ C->get().B->edges.write[C->get().B_edge].C = NULL;
+ C->get().B->edges.write[C->get().B_edge].C_edge = -1;
+ C->get().A->edges.write[C->get().A_edge].C = NULL;
+ C->get().A->edges.write[C->get().A_edge].C_edge = -1;
if (C->get().A == &E->get()) {
@@ -185,11 +183,11 @@ void Navigation::_navmesh_unlink(int p_id) {
C->get().B = cp.polygon;
C->get().B_edge = cp.edge;
- C->get().A->edges[C->get().A_edge].C = cp.polygon;
- C->get().A->edges[C->get().A_edge].C_edge = cp.edge;
- cp.polygon->edges[cp.edge].C = C->get().A;
- cp.polygon->edges[cp.edge].C_edge = C->get().A_edge;
- cp.polygon->edges[cp.edge].P = NULL;
+ C->get().A->edges.write[C->get().A_edge].C = cp.polygon;
+ C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge;
+ cp.polygon->edges.write[cp.edge].C = C->get().A;
+ cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge;
+ cp.polygon->edges.write[cp.edge].P = NULL;
}
} else {
@@ -312,7 +310,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
if (!begin_poly || !end_poly) {
- //print_line("No Path Path");
return Vector<Vector3>(); //no path
}
@@ -320,9 +317,8 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
Vector<Vector3> path;
path.resize(2);
- path[0] = begin_point;
- path[1] = end_point;
- //print_line("Direct Path");
+ path.write[0] = begin_point;
+ path.write[1] = end_point;
return path;
}
@@ -347,7 +343,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
while (!found_route) {
if (open_list.size() == 0) {
- //print_line("NOU OPEN LIST");
break;
}
//check open list
@@ -375,7 +370,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
for (int i = 0; i < p->edges.size(); i++) {
- Polygon::Edge &e = p->edges[i];
+ Polygon::Edge &e = p->edges.write[i];
if (!e.C)
continue;
@@ -581,10 +576,6 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve
}
}
- if (closest_navmesh && closest_navmesh->owner) {
- //print_line("navmesh is: "+Object::cast_to<Node>(closest_navmesh->owner)->get_name());
- }
-
return closest_point;
}
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 073e56fdb4..99680b7273 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -55,9 +55,9 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
for (int j = 0; j < rlen; j += 3) {
Vector<int> vi;
vi.resize(3);
- vi[0] = r[j + 0] + from;
- vi[1] = r[j + 1] + from;
- vi[2] = r[j + 2] + from;
+ vi.write[0] = r[j + 0] + from;
+ vi.write[1] = r[j + 1] + from;
+ vi.write[2] = r[j + 2] + from;
add_polygon(vi);
}
@@ -215,7 +215,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) {
polygons.resize(p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- polygons[i].indices = p_array[i];
+ polygons.write[i].indices = p_array[i];
}
}
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 2b3a62fcdc..10b26778ef 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "particles.h"
-#include "scene/resources/surface_tool.h"
+
#include "servers/visual_server.h"
AABB Particles::get_aabb() const {
@@ -185,7 +185,7 @@ void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
ERR_FAIL_INDEX(p_pass, draw_passes.size());
- draw_passes[p_pass] = p_mesh;
+ draw_passes.write[p_pass] = p_mesh;
RID mesh_rid;
if (p_mesh.is_valid())
@@ -329,7 +329,7 @@ void Particles::_bind_methods() {
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_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, "speed_scale", PROPERTY_HINT_RANGE, "0,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");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
@@ -378,1219 +378,3 @@ Particles::~Particles() {
VS::get_singleton()->free(particles);
}
-
-//////////////////////////////////////
-
-Mutex *ParticlesMaterial::material_mutex = NULL;
-SelfList<ParticlesMaterial>::List ParticlesMaterial::dirty_materials;
-Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map;
-ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = NULL;
-
-void ParticlesMaterial::init_shaders() {
-
-#ifndef NO_THREADS
- material_mutex = Mutex::create();
-#endif
-
- shader_names = memnew(ShaderNames);
-
- shader_names->spread = "spread";
- shader_names->flatness = "flatness";
- shader_names->initial_linear_velocity = "initial_linear_velocity";
- shader_names->initial_angle = "initial_angle";
- shader_names->angular_velocity = "angular_velocity";
- shader_names->orbit_velocity = "orbit_velocity";
- shader_names->linear_accel = "linear_accel";
- shader_names->radial_accel = "radial_accel";
- shader_names->tangent_accel = "tangent_accel";
- shader_names->damping = "damping";
- shader_names->scale = "scale";
- shader_names->hue_variation = "hue_variation";
- shader_names->anim_speed = "anim_speed";
- shader_names->anim_offset = "anim_offset";
-
- shader_names->initial_linear_velocity_random = "initial_linear_velocity_random";
- shader_names->initial_angle_random = "initial_angle_random";
- shader_names->angular_velocity_random = "angular_velocity_random";
- shader_names->orbit_velocity_random = "orbit_velocity_random";
- shader_names->linear_accel_random = "linear_accel_random";
- shader_names->radial_accel_random = "radial_accel_random";
- shader_names->tangent_accel_random = "tangent_accel_random";
- shader_names->damping_random = "damping_random";
- shader_names->scale_random = "scale_random";
- shader_names->hue_variation_random = "hue_variation_random";
- shader_names->anim_speed_random = "anim_speed_random";
- shader_names->anim_offset_random = "anim_offset_random";
-
- shader_names->angle_texture = "angle_texture";
- shader_names->angular_velocity_texture = "angular_velocity_texture";
- shader_names->orbit_velocity_texture = "orbit_velocity_texture";
- shader_names->linear_accel_texture = "linear_accel_texture";
- shader_names->radial_accel_texture = "radial_accel_texture";
- shader_names->tangent_accel_texture = "tangent_accel_texture";
- shader_names->damping_texture = "damping_texture";
- shader_names->scale_texture = "scale_texture";
- shader_names->hue_variation_texture = "hue_variation_texture";
- shader_names->anim_speed_texture = "anim_speed_texture";
- shader_names->anim_offset_texture = "anim_offset_texture";
-
- shader_names->color = "color_value";
- shader_names->color_ramp = "color_ramp";
-
- shader_names->emission_sphere_radius = "emission_sphere_radius";
- shader_names->emission_box_extents = "emission_box_extents";
- shader_names->emission_texture_point_count = "emission_texture_point_count";
- shader_names->emission_texture_points = "emission_texture_points";
- shader_names->emission_texture_normal = "emission_texture_normal";
- shader_names->emission_texture_color = "emission_texture_color";
-
- shader_names->trail_divisor = "trail_divisor";
- shader_names->trail_size_modifier = "trail_size_modifier";
- shader_names->trail_color_modifier = "trail_color_modifier";
-
- shader_names->gravity = "gravity";
-}
-
-void ParticlesMaterial::finish_shaders() {
-
-#ifndef NO_THREADS
- memdelete(material_mutex);
-#endif
-
- memdelete(shader_names);
-}
-
-void ParticlesMaterial::_update_shader() {
-
- dirty_materials.remove(&element);
-
- MaterialKey mk = _compute_key();
- if (mk.key == current_key.key)
- return; //no update required in the end
-
- 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);
- }
- }
-
- current_key = mk;
-
- if (shader_map.has(mk)) {
-
- VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
- shader_map[mk].users++;
- return;
- }
-
- //must create a shader!
-
- String code = "shader_type particles;\n";
-
- code += "uniform float spread;\n";
- code += "uniform float flatness;\n";
- code += "uniform float initial_linear_velocity;\n";
- code += "uniform float initial_angle;\n";
- code += "uniform float angular_velocity;\n";
- code += "uniform float orbit_velocity;\n";
- code += "uniform float linear_accel;\n";
- code += "uniform float radial_accel;\n";
- code += "uniform float tangent_accel;\n";
- code += "uniform float damping;\n";
- code += "uniform float scale;\n";
- code += "uniform float hue_variation;\n";
- code += "uniform float anim_speed;\n";
- code += "uniform float anim_offset;\n";
-
- code += "uniform float initial_linear_velocity_random;\n";
- code += "uniform float initial_angle_random;\n";
- code += "uniform float angular_velocity_random;\n";
- code += "uniform float orbit_velocity_random;\n";
- code += "uniform float linear_accel_random;\n";
- code += "uniform float radial_accel_random;\n";
- code += "uniform float tangent_accel_random;\n";
- code += "uniform float damping_random;\n";
- code += "uniform float scale_random;\n";
- code += "uniform float hue_variation_random;\n";
- code += "uniform float anim_speed_random;\n";
- code += "uniform float anim_offset_random;\n";
-
- switch (emission_shape) {
- case EMISSION_SHAPE_POINT: {
- //do none
- } break;
- case EMISSION_SHAPE_SPHERE: {
- code += "uniform float emission_sphere_radius;\n";
- } break;
- case EMISSION_SHAPE_BOX: {
- code += "uniform vec3 emission_box_extents;\n";
- } break;
- case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += "uniform sampler2D emission_texture_normal : hint_black;\n";
- } //fallthrough
- case EMISSION_SHAPE_POINTS: {
- code += "uniform sampler2D emission_texture_points : hint_black;\n";
- code += "uniform int emission_texture_point_count;\n";
- if (emission_color_texture.is_valid()) {
- code += "uniform sampler2D emission_texture_color : hint_white;\n";
- }
- } break;
- }
-
- code += "uniform vec4 color_value : hint_color;\n";
-
- code += "uniform int trail_divisor;\n";
-
- code += "uniform vec3 gravity;\n";
-
- if (color_ramp.is_valid())
- code += "uniform sampler2D color_ramp;\n";
-
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
- code += "uniform sampler2D linear_velocity_texture;\n";
- if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
- code += "uniform sampler2D orbit_velocity_texture;\n";
- if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
- code += "uniform sampler2D angular_velocity_texture;\n";
- if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
- code += "uniform sampler2D linear_accel_texture;\n";
- if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
- code += "uniform sampler2D radial_accel_texture;\n";
- if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
- code += "uniform sampler2D tangent_accel_texture;\n";
- if (tex_parameters[PARAM_DAMPING].is_valid())
- code += "uniform sampler2D damping_texture;\n";
- if (tex_parameters[PARAM_ANGLE].is_valid())
- code += "uniform sampler2D angle_texture;\n";
- if (tex_parameters[PARAM_SCALE].is_valid())
- code += "uniform sampler2D scale_texture;\n";
- if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
- code += "uniform sampler2D hue_variation_texture;\n";
- if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
- code += "uniform sampler2D anim_speed_texture;\n";
- if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
- code += "uniform sampler2D anim_offset_texture;\n";
-
- if (trail_size_modifier.is_valid()) {
- code += "uniform sampler2D trail_size_modifier;\n";
- }
-
- if (trail_color_modifier.is_valid()) {
- code += "uniform sampler2D trail_color_modifier;\n";
- }
-
- //need a random function
- code += "\n\n";
- code += "float rand_from_seed(inout uint seed) {\n";
- code += " int k;\n";
- code += " int s = int(seed);\n";
- code += " if (s == 0)\n";
- code += " s = 305420679;\n";
- code += " k = s / 127773;\n";
- code += " s = 16807 * (s - k * 127773) - 2836 * k;\n";
- code += " if (s < 0)\n";
- code += " s += 2147483647;\n";
- code += " seed = uint(s);\n";
- code += " return float(seed % uint(65536))/65535.0;\n";
- 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";
- code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
- code += " x = (x >> uint(16)) ^ x;\n";
- code += " return x;\n";
- code += "}\n";
- code += "\n";
-
- code += "void vertex() {\n";
- code += " uint base_number = NUMBER/uint(trail_divisor);\n";
- code += " uint alt_seed = hash(base_number+uint(1)+RANDOM_SEED);\n";
- code += " float angle_rand = rand_from_seed(alt_seed);\n";
- 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) {
- code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
- code += " ivec2 emission_tex_size = textureSize( emission_texture_points, 0 );\n";
- code += " ivec2 emission_tex_ofs = ivec2( point % emission_tex_size.x, point / emission_tex_size.x );\n";
- }
- code += " if (RESTART) {\n";
-
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(0.0,0.0),0.0).r;\n";
- else
- code += " float tex_linear_velocity = 0.0;\n";
-
- if (tex_parameters[PARAM_ANGLE].is_valid())
- code += " float tex_angle = textureLod(angle_texture,vec2(0.0,0.0),0.0).r;\n";
- else
- code += " float tex_angle = 0.0;\n";
-
- if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
- code += " float tex_anim_offset = textureLod(anim_offset_texture,vec2(0.0,0.0),0.0).r;\n";
- 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_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_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*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) {
- case EMISSION_SHAPE_POINT: {
- //do none
- } break;
- case EMISSION_SHAPE_SPHERE: {
- code += " TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0 ))*emission_sphere_radius;\n";
- } break;
- case EMISSION_SHAPE_BOX: {
- code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0)*emission_box_extents;\n";
- } break;
- case EMISSION_SHAPE_POINTS:
- case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs,0).xyz;\n";
-
- if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
- if (flags[FLAG_DISABLE_Z]) {
-
- code += " mat2 rotm;";
- code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs,0).xy;\n";
- code += " rotm[1] = rotm[0].yx * vec2(1.0,-1.0);\n";
- code += " VELOCITY.xy = rotm * VELOCITY.xy;\n";
- } else {
- code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs,0).xyz;\n";
- code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n";
- code += " vec3 tangent = normalize(cross(v0, normal));\n";
- code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
- code += " VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n";
- }
- }
- } break;
- }
- code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n";
- code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
- if (flags[FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
- }
-
- code += " } else {\n";
-
- code += " CUSTOM.y += DELTA/LIFETIME;\n";
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_linear_velocity = 0.0;\n";
-
- if (flags[FLAG_DISABLE_Z]) {
-
- if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
- code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_orbit_velocity = 0.0;\n";
- }
-
- if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
- code += " float tex_angular_velocity = textureLod(angular_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_angular_velocity = 0.0;\n";
-
- if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
- code += " float tex_linear_accel = textureLod(linear_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_linear_accel = 0.0;\n";
-
- if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
- code += " float tex_radial_accel = textureLod(radial_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_radial_accel = 0.0;\n";
-
- if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
- code += " float tex_tangent_accel = textureLod(tangent_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_tangent_accel = 0.0;\n";
-
- if (tex_parameters[PARAM_DAMPING].is_valid())
- code += " float tex_damping = textureLod(damping_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_damping = 0.0;\n";
-
- if (tex_parameters[PARAM_ANGLE].is_valid())
- code += " float tex_angle = textureLod(angle_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_angle = 0.0;\n";
-
- if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
- code += " float tex_anim_speed = textureLod(anim_speed_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_anim_speed = 0.0;\n";
-
- if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
- code += " float tex_anim_offset = textureLod(anim_offset_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_anim_offset = 0.0;\n";
-
- code += " vec3 force = gravity; \n";
- code += " vec3 pos = TRANSFORM[3].xyz; \n";
- if (flags[FLAG_DISABLE_Z]) {
- code += " pos.z = 0.0; \n";
- }
- code += " //apply linear acceleration\n";
- code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random) : vec3(0.0);\n";
- code += " //apply radial acceleration\n";
- code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
- code += " vec3 diff = pos-org;\n";
- code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random) : vec3(0.0);\n";
- code += " //apply tangential acceleration;\n";
- if (flags[FLAG_DISABLE_Z]) {
- code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0,1.0)),0.0) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),tangent_accel_random)) : vec3(0.0);\n";
-
- } else {
- code += " vec3 crossDiff = cross(normalize(diff),normalize(gravity));\n";
- code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),tangent_accel_random)) : vec3(0.0);\n";
- }
- code += " //apply attractor forces\n";
- code += " VELOCITY += force * DELTA;\n";
- code += " //orbit velocity\n";
- if (flags[FLAG_DISABLE_Z]) {
-
- 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 * 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";
- code += " }\n";
- }
-
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " VELOCITY = normalize(VELOCITY)*tex_linear_velocity;\n";
- }
- code += " if (damping + tex_damping > 0.0) {\n";
- code += " \n";
- code += " float v = length(VELOCITY);\n";
- code += " float damp = (damping+tex_damping)*mix(1.0,rand_from_seed(alt_seed),damping_random);\n";
- code += " v -= damp * DELTA;\n";
- code += " if (v < 0.0) {\n";
- code += " VELOCITY = vec3(0.0);\n";
- code += " } else {\n";
- code += " VELOCITY = normalize(VELOCITY) * v;\n";
- code += " }\n";
- 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*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
-
- } else {
- code += " CUSTOM.z = clamp(CUSTOM.z,0.0,1.0);\n"; //0 to 1 only
- }
- code += " }\n";
- //apply color
- //apply hue rotation
- if (tex_parameters[PARAM_SCALE].is_valid())
- code += " float tex_scale = textureLod(scale_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_scale = 1.0;\n";
-
- if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
- code += " float tex_hue_variation = textureLod(hue_variation_texture,vec2(CUSTOM.y,0.0),0.0).r;\n";
- else
- code += " float tex_hue_variation = 0.0;\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";
- code += " vec4(0.299, 0.587, 0.114, 0.0),\n";
- code += " vec4(0.299, 0.587, 0.114, 0.0),\n";
- code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n";
- code += " mat4( vec4(0.701, -0.587, -0.114, 0.0),\n";
- code += " vec4(-0.299, 0.413, -0.114, 0.0),\n";
- code += " vec4(-0.300, -0.588, 0.886, 0.0),\n";
- code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n";
- code += " mat4( vec4(0.168, 0.330, -0.497, 0.0),\n";
- code += " vec4(-0.328, 0.035, 0.292, 0.0),\n";
- 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 = hue_rot_mat * textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0);\n";
- } else {
- 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";
- }
- if (trail_color_modifier.is_valid()) {
- code += " if (trail_divisor > 1) { COLOR *= textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n";
- }
- code += "\n";
-
- if (flags[FLAG_DISABLE_Z]) {
-
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
- code += " if (length(VELOCITY) > 0.0) { TRANSFORM[1].xyz = normalize(VELOCITY); } else { TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz); }\n";
- code += " TRANSFORM[0].xyz = normalize(cross(TRANSFORM[1].xyz,TRANSFORM[2].xyz));\n";
- code += " TRANSFORM[2] = vec4(0.0,0.0,1.0,0.0);\n";
- } else {
- code += " TRANSFORM[0] = vec4(cos(CUSTOM.x),-sin(CUSTOM.x),0.0,0.0);\n";
- code += " TRANSFORM[1] = vec4(sin(CUSTOM.x),cos(CUSTOM.x),0.0,0.0);\n";
- code += " TRANSFORM[2] = vec4(0.0,0.0,1.0,0.0);\n";
- }
-
- } else {
- //orient particle Y towards velocity
- if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
- code += " if (length(VELOCITY) > 0.0) { TRANSFORM[1].xyz = normalize(VELOCITY); } else { TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz); }\n";
- code += " if (TRANSFORM[1].xyz == normalize(TRANSFORM[0].xyz)) {\n";
- code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
- code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
- code += " } else {\n";
- code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n";
- code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n";
- code += " }\n";
- } else {
- code += " TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);\n";
- code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n";
- code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n";
- }
- //turn particle by rotation in Y
- if (flags[FLAG_ROTATE_Y]) {
- code += " TRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n";
- }
- }
- //scale by scale
- code += " float base_scale = mix(scale*tex_scale,1.0,scale_random*scale_rand);\n";
- code += " if (base_scale==0.0) base_scale=0.000001;\n";
- if (trail_size_modifier.is_valid()) {
- code += " if (trail_divisor > 1) { base_scale *= textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n";
- }
-
- code += " TRANSFORM[0].xyz *= base_scale;\n";
- code += " TRANSFORM[1].xyz *= base_scale;\n";
- code += " TRANSFORM[2].xyz *= base_scale;\n";
- if (flags[FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
- }
- code += "}\n";
- code += "\n";
-
- ShaderData shader_data;
- shader_data.shader = VS::get_singleton()->shader_create();
- shader_data.users = 1;
-
- VS::get_singleton()->shader_set_code(shader_data.shader, code);
-
- shader_map[mk] = shader_data;
-
- VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
-}
-
-void ParticlesMaterial::flush_changes() {
-
- if (material_mutex)
- material_mutex->lock();
-
- while (dirty_materials.first()) {
-
- dirty_materials.first()->self()->_update_shader();
- }
-
- if (material_mutex)
- material_mutex->unlock();
-}
-
-void ParticlesMaterial::_queue_shader_change() {
-
- if (material_mutex)
- material_mutex->lock();
-
- if (!element.in_list()) {
- dirty_materials.add(&element);
- }
-
- if (material_mutex)
- material_mutex->unlock();
-}
-
-bool ParticlesMaterial::_is_shader_dirty() const {
-
- bool dirty = false;
-
- if (material_mutex)
- material_mutex->lock();
-
- dirty = element.in_list();
-
- if (material_mutex)
- material_mutex->unlock();
-
- return dirty;
-}
-
-void ParticlesMaterial::set_spread(float p_spread) {
-
- spread = p_spread;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
-}
-
-float ParticlesMaterial::get_spread() const {
-
- return spread;
-}
-
-void ParticlesMaterial::set_flatness(float p_flatness) {
-
- flatness = p_flatness;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
-}
-float ParticlesMaterial::get_flatness() const {
-
- return flatness;
-}
-
-void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- parameters[p_param] = p_value;
-
- switch (p_param) {
- case PARAM_INITIAL_LINEAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value);
- } break;
- case PARAM_ANGULAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value);
- } break;
- case PARAM_ORBIT_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value);
- } break;
- case PARAM_LINEAR_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value);
- } break;
- case PARAM_RADIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value);
- } break;
- case PARAM_TANGENTIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value);
- } break;
- case PARAM_DAMPING: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value);
- } break;
- case PARAM_ANGLE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value);
- } break;
- case PARAM_SCALE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value);
- } break;
- case PARAM_HUE_VARIATION: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value);
- } break;
- case PARAM_ANIM_SPEED: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value);
- } break;
- case PARAM_ANIM_OFFSET: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
- } break;
- }
-}
-float ParticlesMaterial::get_param(Parameter p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
-
- return parameters[p_param];
-}
-
-void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- randomness[p_param] = p_value;
-
- switch (p_param) {
- case PARAM_INITIAL_LINEAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value);
- } break;
- case PARAM_ANGULAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value);
- } break;
- case PARAM_ORBIT_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value);
- } break;
- case PARAM_LINEAR_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value);
- } break;
- case PARAM_RADIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value);
- } break;
- case PARAM_TANGENTIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value);
- } break;
- case PARAM_DAMPING: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value);
- } break;
- case PARAM_ANGLE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value);
- } break;
- case PARAM_SCALE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value);
- } break;
- case PARAM_HUE_VARIATION: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value);
- } break;
- case PARAM_ANIM_SPEED: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value);
- } break;
- case PARAM_ANIM_OFFSET: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
- } break;
- }
-}
-float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
-
- return randomness[p_param];
-}
-
-static void _adjust_curve_range(const Ref<Texture> &p_texture, float p_min, float p_max) {
-
- Ref<CurveTexture> curve_tex = p_texture;
- if (!curve_tex.is_valid())
- return;
-
- curve_tex->ensure_default_setup(p_min, p_max);
-}
-
-void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> &p_texture) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- tex_parameters[p_param] = p_texture;
-
- switch (p_param) {
- case PARAM_INITIAL_LINEAR_VELOCITY: {
- //do none for this one
- } break;
- case PARAM_ANGULAR_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture);
- _adjust_curve_range(p_texture, -360, 360);
- } break;
- case PARAM_ORBIT_VELOCITY: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture);
- _adjust_curve_range(p_texture, -500, 500);
- } break;
- case PARAM_LINEAR_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture);
- _adjust_curve_range(p_texture, -200, 200);
- } break;
- case PARAM_RADIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture);
- _adjust_curve_range(p_texture, -200, 200);
- } break;
- case PARAM_TANGENTIAL_ACCEL: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture);
- _adjust_curve_range(p_texture, -200, 200);
- } break;
- case PARAM_DAMPING: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture);
- _adjust_curve_range(p_texture, 0, 100);
- } break;
- case PARAM_ANGLE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture);
- _adjust_curve_range(p_texture, -360, 360);
- } break;
- case PARAM_SCALE: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture);
-
- Ref<CurveTexture> curve_tex = p_texture;
- if (curve_tex.is_valid()) {
- curve_tex->ensure_default_setup();
- }
-
- } break;
- case PARAM_HUE_VARIATION: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture);
- _adjust_curve_range(p_texture, -1, 1);
- } break;
- case PARAM_ANIM_SPEED: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture);
- _adjust_curve_range(p_texture, 0, 200);
- } break;
- case PARAM_ANIM_OFFSET: {
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
- } break;
- }
-
- _queue_shader_change();
-}
-Ref<Texture> ParticlesMaterial::get_param_texture(Parameter p_param) const {
-
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture>());
-
- return tex_parameters[p_param];
-}
-
-void ParticlesMaterial::set_color(const Color &p_color) {
-
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
- color = p_color;
-}
-
-Color ParticlesMaterial::get_color() const {
-
- return color;
-}
-
-void ParticlesMaterial::set_color_ramp(const Ref<Texture> &p_texture) {
-
- color_ramp = p_texture;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture);
- _queue_shader_change();
- _change_notify();
-}
-
-Ref<Texture> ParticlesMaterial::get_color_ramp() const {
-
- return color_ramp;
-}
-
-void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) {
- ERR_FAIL_INDEX(p_flag, FLAG_MAX);
- flags[p_flag] = p_enable;
- _queue_shader_change();
- if (p_flag == FLAG_DISABLE_Z) {
- _change_notify();
- }
-}
-
-bool ParticlesMaterial::get_flag(Flags p_flag) const {
- ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
- return flags[p_flag];
-}
-
-void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
-
- emission_shape = p_shape;
- _change_notify();
- _queue_shader_change();
-}
-
-void ParticlesMaterial::set_emission_sphere_radius(float p_radius) {
-
- emission_sphere_radius = p_radius;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
-}
-
-void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
-
- emission_box_extents = p_extents;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
-}
-
-void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) {
-
- emission_point_texture = p_points;
- 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;
- 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;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors);
- _queue_shader_change();
-}
-
-void ParticlesMaterial::set_emission_point_count(int p_count) {
-
- emission_point_count = p_count;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
-}
-
-ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const {
-
- return emission_shape;
-}
-
-float ParticlesMaterial::get_emission_sphere_radius() const {
-
- return emission_sphere_radius;
-}
-Vector3 ParticlesMaterial::get_emission_box_extents() const {
-
- return emission_box_extents;
-}
-Ref<Texture> ParticlesMaterial::get_emission_point_texture() const {
-
- return emission_point_texture;
-}
-Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const {
-
- return emission_normal_texture;
-}
-
-Ref<Texture> ParticlesMaterial::get_emission_color_texture() const {
-
- return emission_color_texture;
-}
-
-int ParticlesMaterial::get_emission_point_count() const {
-
- return emission_point_count;
-}
-
-void ParticlesMaterial::set_trail_divisor(int p_divisor) {
-
- trail_divisor = p_divisor;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor);
-}
-
-int ParticlesMaterial::get_trail_divisor() const {
-
- return trail_divisor;
-}
-
-void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) {
-
- trail_size_modifier = p_trail_size_modifier;
-
- Ref<CurveTexture> curve = trail_size_modifier;
- if (curve.is_valid()) {
- curve->ensure_default_setup();
- }
-
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
- _queue_shader_change();
-}
-
-Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
-
- return trail_size_modifier;
-}
-
-void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
-
- trail_color_modifier = p_trail_color_modifier;
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
- _queue_shader_change();
-}
-
-Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const {
-
- return trail_color_modifier;
-}
-
-void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
-
- gravity = p_gravity;
- Vector3 gset = gravity;
- if (gset == Vector3()) {
- gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations
- }
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset);
-}
-
-Vector3 ParticlesMaterial::get_gravity() const {
-
- return gravity;
-}
-
-RID ParticlesMaterial::get_shader_rid() const {
-
- ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
- return shader_map[current_key].shader;
-}
-
-void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
-
- if (property.name == "color" && color_ramp.is_valid()) {
- property.usage = 0;
- }
-
- if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
- property.usage = 0;
- }
-
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = 0;
- }
-
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
- property.usage = 0;
- }
-
- if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = 0;
- }
-
- if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = 0;
- }
-
- if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
- property.usage = 0;
- }
-}
-
-Shader::Mode ParticlesMaterial::get_shader_mode() const {
-
- return Shader::MODE_PARTICLES;
-}
-
-void ParticlesMaterial::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread);
- ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread);
-
- ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness);
- ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ParticlesMaterial::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &ParticlesMaterial::get_param);
-
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &ParticlesMaterial::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &ParticlesMaterial::get_param_randomness);
-
- ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture);
- ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
-
- ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color);
-
- ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp);
- ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp);
-
- ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag);
- ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag);
-
- ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape);
- ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape);
-
- ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius);
- ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius);
-
- ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents);
- ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents);
-
- ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture);
- ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture);
-
- ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture);
- ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture);
-
- ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture);
- ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture);
-
- ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count);
- ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count);
-
- ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor);
- ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor);
-
- ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture"), &ParticlesMaterial::set_trail_size_modifier);
- ClassDB::bind_method(D_METHOD("get_trail_size_modifier"), &ParticlesMaterial::get_trail_size_modifier);
-
- ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture"), &ParticlesMaterial::set_trail_color_modifier);
- ClassDB::bind_method(D_METHOD("get_trail_color_modifier"), &ParticlesMaterial::get_trail_color_modifier);
-
- ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity);
- ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity);
-
- ADD_GROUP("Trail", "trail_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier");
- ADD_GROUP("Emission Shape", "emission_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_color_texture", "get_emission_color_texture");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count");
- ADD_GROUP("Flags", "flag_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z);
- ADD_GROUP("Spread", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
- 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,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,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,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,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,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", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING);
- 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,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,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", "");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp");
-
- ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION);
- 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,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);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP);
-
- BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
- BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
- BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
- BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
- BIND_ENUM_CONSTANT(PARAM_DAMPING);
- BIND_ENUM_CONSTANT(PARAM_ANGLE);
- BIND_ENUM_CONSTANT(PARAM_SCALE);
- BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
- BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
- BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
- BIND_ENUM_CONSTANT(PARAM_MAX);
-
- BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
- BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
- BIND_ENUM_CONSTANT(FLAG_MAX);
-
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
- BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
-}
-
-ParticlesMaterial::ParticlesMaterial() :
- element(this) {
-
- set_spread(45);
- set_flatness(0);
- set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1);
- set_param(PARAM_ORBIT_VELOCITY, 0);
- set_param(PARAM_LINEAR_ACCEL, 0);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_DAMPING, 0);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- set_param(PARAM_HUE_VARIATION, 0);
- set_param(PARAM_ANIM_SPEED, 0);
- set_param(PARAM_ANIM_OFFSET, 0);
- set_emission_shape(EMISSION_SHAPE_POINT);
- set_emission_sphere_radius(1);
- set_emission_box_extents(Vector3(1, 1, 1));
- set_trail_divisor(1);
- set_gravity(Vector3(0, -9.8, 0));
- emission_point_count = 1;
-
- for (int i = 0; i < PARAM_MAX; i++) {
- set_param_randomness(Parameter(i), 0);
- }
-
- for (int i = 0; i < FLAG_MAX; i++) {
- flags[i] = false;
- }
-
- set_color(Color(1, 1, 1, 1));
-
- current_key.key = 0;
- current_key.invalid_key = 1;
-
- _queue_shader_change();
-}
-
-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 17e21c6cee..742246f78c 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -28,12 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VISUALINSTANCEPARTICLES_H
-#define VISUALINSTANCEPARTICLES_H
+#ifndef PARTICLES_H
+#define PARTICLES_H
#include "rid.h"
#include "scene/3d/visual_instance.h"
-#include "scene/main/timer.h"
#include "scene/resources/material.h"
/**
@@ -135,269 +134,4 @@ public:
VARIANT_ENUM_CAST(Particles::DrawOrder)
-class ParticlesMaterial : public Material {
-
- GDCLASS(ParticlesMaterial, Material)
-
-public:
- enum Parameter {
-
- PARAM_INITIAL_LINEAR_VELOCITY,
- PARAM_ANGULAR_VELOCITY,
- PARAM_ORBIT_VELOCITY,
- PARAM_LINEAR_ACCEL,
- PARAM_RADIAL_ACCEL,
- PARAM_TANGENTIAL_ACCEL,
- PARAM_DAMPING,
- PARAM_ANGLE,
- PARAM_SCALE,
- PARAM_HUE_VARIATION,
- PARAM_ANIM_SPEED,
- PARAM_ANIM_OFFSET,
- PARAM_MAX
- };
-
- enum Flags {
- FLAG_ALIGN_Y_TO_VELOCITY,
- FLAG_ROTATE_Y,
- FLAG_DISABLE_Z,
- FLAG_ANIM_LOOP,
- FLAG_MAX
- };
-
- enum EmissionShape {
- EMISSION_SHAPE_POINT,
- EMISSION_SHAPE_SPHERE,
- EMISSION_SHAPE_BOX,
- EMISSION_SHAPE_POINTS,
- EMISSION_SHAPE_DIRECTED_POINTS,
- };
-
-private:
- union MaterialKey {
-
- struct {
- uint32_t texture_mask : 16;
- uint32_t texture_color : 1;
- uint32_t flags : 4;
- uint32_t emission_shape : 2;
- uint32_t trail_size_texture : 1;
- uint32_t trail_color_texture : 1;
- uint32_t invalid_key : 1;
- uint32_t has_emission_color : 1;
- };
-
- uint32_t key;
-
- bool operator<(const MaterialKey &p_key) const {
- return key < p_key.key;
- }
- };
-
- struct ShaderData {
- RID shader;
- int users;
- };
-
- static Map<MaterialKey, ShaderData> shader_map;
-
- MaterialKey current_key;
-
- _FORCE_INLINE_ MaterialKey _compute_key() const {
-
- MaterialKey mk;
- mk.key = 0;
- for (int i = 0; i < PARAM_MAX; i++) {
- if (tex_parameters[i].is_valid()) {
- mk.texture_mask |= (1 << i);
- }
- }
- for (int i = 0; i < FLAG_MAX; i++) {
- if (flags[i]) {
- mk.flags |= (1 << i);
- }
- }
-
- mk.texture_color = color_ramp.is_valid() ? 1 : 0;
- mk.emission_shape = emission_shape;
- mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0;
- mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0;
- mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
-
- return mk;
- }
-
- static Mutex *material_mutex;
- static SelfList<ParticlesMaterial>::List dirty_materials;
-
- struct ShaderNames {
- StringName spread;
- StringName flatness;
- StringName initial_linear_velocity;
- StringName initial_angle;
- StringName angular_velocity;
- StringName orbit_velocity;
- StringName linear_accel;
- StringName radial_accel;
- StringName tangent_accel;
- StringName damping;
- StringName scale;
- StringName hue_variation;
- StringName anim_speed;
- StringName anim_offset;
-
- StringName initial_linear_velocity_random;
- StringName initial_angle_random;
- StringName angular_velocity_random;
- StringName orbit_velocity_random;
- StringName linear_accel_random;
- StringName radial_accel_random;
- StringName tangent_accel_random;
- StringName damping_random;
- StringName scale_random;
- StringName hue_variation_random;
- StringName anim_speed_random;
- StringName anim_offset_random;
-
- StringName angle_texture;
- StringName angular_velocity_texture;
- StringName orbit_velocity_texture;
- StringName linear_accel_texture;
- StringName radial_accel_texture;
- StringName tangent_accel_texture;
- StringName damping_texture;
- StringName scale_texture;
- StringName hue_variation_texture;
- StringName anim_speed_texture;
- StringName anim_offset_texture;
-
- StringName color;
- StringName color_ramp;
-
- StringName emission_sphere_radius;
- StringName emission_box_extents;
- StringName emission_texture_point_count;
- StringName emission_texture_points;
- StringName emission_texture_normal;
- StringName emission_texture_color;
-
- StringName trail_divisor;
- StringName trail_size_modifier;
- StringName trail_color_modifier;
-
- StringName gravity;
- };
-
- static ShaderNames *shader_names;
-
- SelfList<ParticlesMaterial> element;
-
- void _update_shader();
- _FORCE_INLINE_ void _queue_shader_change();
- _FORCE_INLINE_ bool _is_shader_dirty() const;
-
- float spread;
- float flatness;
-
- float parameters[PARAM_MAX];
- float randomness[PARAM_MAX];
-
- Ref<Texture> tex_parameters[PARAM_MAX];
- Color color;
- Ref<Texture> color_ramp;
-
- bool flags[FLAG_MAX];
-
- EmissionShape emission_shape;
- float emission_sphere_radius;
- Vector3 emission_box_extents;
- Ref<Texture> emission_point_texture;
- Ref<Texture> emission_normal_texture;
- Ref<Texture> emission_color_texture;
- int emission_point_count;
-
- bool anim_loop;
-
- int trail_divisor;
-
- Ref<CurveTexture> trail_size_modifier;
- Ref<GradientTexture> trail_color_modifier;
-
- Vector3 gravity;
-
- //do not save emission points here
-
-protected:
- static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const;
-
-public:
- void set_spread(float p_spread);
- float get_spread() const;
-
- void set_flatness(float p_flatness);
- float get_flatness() const;
-
- void set_param(Parameter p_param, float p_value);
- float get_param(Parameter p_param) const;
-
- void set_param_randomness(Parameter p_param, float p_value);
- float get_param_randomness(Parameter p_param) const;
-
- void set_param_texture(Parameter p_param, const Ref<Texture> &p_texture);
- Ref<Texture> get_param_texture(Parameter p_param) const;
-
- void set_color(const Color &p_color);
- Color get_color() const;
-
- void set_color_ramp(const Ref<Texture> &p_texture);
- Ref<Texture> get_color_ramp() const;
-
- void set_flag(Flags p_flag, bool p_enable);
- bool get_flag(Flags p_flag) const;
-
- void set_emission_shape(EmissionShape p_shape);
- void set_emission_sphere_radius(float p_radius);
- void set_emission_box_extents(Vector3 p_extents);
- void set_emission_point_texture(const Ref<Texture> &p_points);
- void set_emission_normal_texture(const Ref<Texture> &p_normals);
- void set_emission_color_texture(const Ref<Texture> &p_colors);
- void set_emission_point_count(int p_count);
-
- EmissionShape get_emission_shape() const;
- float get_emission_sphere_radius() const;
- Vector3 get_emission_box_extents() const;
- Ref<Texture> get_emission_point_texture() const;
- Ref<Texture> get_emission_normal_texture() const;
- Ref<Texture> get_emission_color_texture() const;
- int get_emission_point_count() const;
-
- void set_trail_divisor(int p_divisor);
- int get_trail_divisor() const;
-
- void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier);
- Ref<CurveTexture> get_trail_size_modifier() const;
-
- void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier);
- Ref<GradientTexture> get_trail_color_modifier() const;
-
- void set_gravity(const Vector3 &p_gravity);
- Vector3 get_gravity() const;
-
- static void init_shaders();
- static void finish_shaders();
- static void flush_changes();
-
- RID get_shader_rid() const;
-
- virtual Shader::Mode get_shader_mode() const;
-
- ParticlesMaterial();
- ~ParticlesMaterial();
-};
-
-VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
-VARIANT_ENUM_CAST(ParticlesMaterial::Flags)
-VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
-
-#endif
+#endif // PARTICLES_H
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 5056fb2fe4..f7af6a57dd 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -30,6 +30,7 @@
#include "physics_body.h"
+#include "core/core_string_names.h"
#include "engine.h"
#include "method_bind_ext.gen.inc"
#include "scene/scene_string_names.h"
@@ -39,17 +40,6 @@
#endif
void PhysicsBody::_notification(int p_what) {
-
- /*
- switch(p_what) {
-
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
-
- } break;
- }
- */
}
Vector3 PhysicsBody::get_linear_velocity() const {
@@ -121,23 +111,23 @@ bool PhysicsBody::get_collision_layer_bit(int p_bit) const {
void PhysicsBody::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
- PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node);
- if (!physics_body) {
- ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
}
- ERR_FAIL_COND(!physics_body);
- PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid());
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid());
}
void PhysicsBody::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
- PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node);
- if (!physics_body) {
- ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type");
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
}
- ERR_FAIL_COND(!physics_body);
- PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid());
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
void PhysicsBody::_set_layers(uint32_t p_mask) {
@@ -178,28 +168,84 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) :
collision_mask = 1;
}
+#ifndef DISABLE_DEPRECATED
void StaticBody::set_friction(real_t p_friction) {
+ if (p_friction == 1.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
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);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_friction(p_friction);
}
+
real_t StaticBody::get_friction() const {
- return friction;
+ ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 1;
+ }
+
+ return physics_material_override->get_friction();
}
void StaticBody::set_bounce(real_t p_bounce) {
+ if (p_bounce == 0.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
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);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_bounce(p_bounce);
}
+
real_t StaticBody::get_bounce() const {
- return bounce;
+ ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 0;
+ }
+
+ return physics_material_override->get_bounce();
+}
+#endif
+
+void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> StaticBody::get_physics_material_override() const {
+ return physics_material_override;
}
void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) {
@@ -230,30 +276,45 @@ void StaticBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody::get_constant_linear_velocity);
ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody::get_constant_angular_velocity);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &StaticBody::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &StaticBody::get_friction);
ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce);
ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with);
- 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");
-
+#ifndef DISABLE_DEPRECATED
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+#endif // DISABLE_DEPRECATED
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
}
StaticBody::StaticBody() :
PhysicsBody(PhysicsServer::BODY_MODE_STATIC) {
-
- bounce = 0;
- friction = 1;
}
-StaticBody::~StaticBody() {
+StaticBody::~StaticBody() {}
+
+void StaticBody::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
}
void RigidBody::_body_enter_tree(ObjectID p_id) {
@@ -354,7 +415,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,
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);
if (in_tree)
- emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
+ emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
contact_monitor->body_map.erase(E);
@@ -550,28 +611,80 @@ real_t RigidBody::get_weight() const {
return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
}
+#ifndef DISABLE_DEPRECATED
void RigidBody::set_friction(real_t p_friction) {
+ if (p_friction == 1.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
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);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_friction(p_friction);
}
real_t RigidBody::get_friction() const {
- return friction;
+ ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
+ if (physics_material_override.is_null()) {
+ return 1;
+ }
+
+ return physics_material_override->get_friction();
}
void RigidBody::set_bounce(real_t p_bounce) {
+ if (p_bounce == 0.0) { // default value, don't create an override for that
+ return;
+ }
+
+ ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+
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);
+ if (physics_material_override.is_null()) {
+ physics_material_override.instance();
+ set_physics_material_override(physics_material_override);
+ }
+ physics_material_override->set_bounce(p_bounce);
}
real_t RigidBody::get_bounce() const {
+ ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.")
+ WARN_DEPRECATED
+ if (physics_material_override.is_null()) {
+ return 0;
+ }
- return bounce;
+ return physics_material_override->get_bounce();
+}
+#endif // DISABLE_DEPRECATED
+
+void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+ if (physics_material_override.is_valid()) {
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"))
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+
+ physics_material_override = p_physics_material_override;
+
+ if (physics_material_override.is_valid()) {
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+ }
+ _reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> RigidBody::get_physics_material_override() const {
+ return physics_material_override;
}
void RigidBody::set_gravity_scale(real_t p_gravity_scale) {
@@ -693,6 +806,22 @@ int RigidBody::get_max_contacts_reported() const {
return max_contacts_reported;
}
+void RigidBody::add_central_force(const Vector3 &p_force) {
+ PhysicsServer::get_singleton()->body_add_central_force(get_rid(), p_force);
+}
+
+void RigidBody::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
+ PhysicsServer::get_singleton()->body_add_force(get_rid(), p_force, p_pos);
+}
+
+void RigidBody::add_torque(const Vector3 &p_torque) {
+ PhysicsServer::get_singleton()->body_add_torque(get_rid(), p_torque);
+}
+
+void RigidBody::apply_central_impulse(const Vector3 &p_impulse) {
+ PhysicsServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
+}
+
void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
@@ -806,11 +935,18 @@ void RigidBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody::set_weight);
ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody::get_weight);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_friction", "friction"), &RigidBody::set_friction);
ClassDB::bind_method(D_METHOD("get_friction"), &RigidBody::get_friction);
ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce);
ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override);
+
+ ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody::_reload_physics_characteristics);
ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity);
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity);
@@ -840,6 +976,12 @@ void RigidBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody::is_using_continuous_collision_detection);
ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity);
+
+ ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody::add_central_force);
+ ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody::add_force);
+ ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody::add_torque);
+
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody::apply_central_impulse);
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);
@@ -863,8 +1005,11 @@ void RigidBody::_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, "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");
+#ifndef DISABLE_DEPRECATED
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce");
+#endif // DISABLE_DEPRECATED
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
@@ -886,10 +1031,10 @@ void RigidBody::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "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_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")));
- ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body")));
- ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body")));
+ ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), 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", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
+ ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("sleeping_state_changed"));
BIND_ENUM_CONSTANT(MODE_RIGID);
@@ -903,9 +1048,7 @@ RigidBody::RigidBody() :
mode = MODE_RIGID;
- bounce = 0;
mass = 1;
- friction = 1;
max_contacts_reported = 0;
state = NULL;
@@ -929,13 +1072,24 @@ RigidBody::~RigidBody() {
if (contact_monitor)
memdelete(contact_monitor);
}
+
+void RigidBody::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
+}
+
//////////////////////////////////////////////////////
//////////////////////////
-Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia) {
+Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_test_only) {
Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -949,7 +1103,7 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf
return Ref<KinematicCollision>();
}
-bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision) {
+bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_test_only) {
Transform gt = get_global_transform();
PhysicsServer::MotionResult result;
@@ -962,6 +1116,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
r_collision.collision = result.collision_point;
r_collision.normal = result.collision_normal;
r_collision.collider = result.collider_id;
+ r_collision.collider_rid = result.collider;
r_collision.travel = result.motion;
r_collision.remainder = result.remainder;
r_collision.local_shape = result.collision_local_shape;
@@ -973,13 +1128,18 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
}
}
- gt.origin += result.motion;
- set_global_transform(gt);
+ if (!p_test_only) {
+ gt.origin += result.motion;
+ set_global_transform(gt);
+ }
return colliding;
}
-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) {
+//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+#define FLOOR_ANGLE_THRESHOLD 0.01
+
+Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector3 lv = p_linear_velocity;
@@ -997,69 +1157,127 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
colliders.clear();
floor_velocity = Vector3();
+ Vector3 lv_n = p_linear_velocity.normalized();
+
while (p_max_slides) {
Collision collision;
- bool collided = move_and_collide(motion, p_infinite_inertia, collision);
-
- if (collided) {
+ bool found_collision = false;
- motion = collision.remainder;
+ int test_type = 0;
- if (p_floor_direction == Vector3()) {
- //all is a wall
- on_wall = true;
+ do {
+ bool collided;
+ if (test_type == 0) { //collide
+ collided = move_and_collide(motion, p_infinite_inertia, collision);
+ if (!collided) {
+ motion = Vector3(); //clear because no collision happened and motion completed
+ }
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ if (collided) {
+ collision.remainder = motion; //keep
+ collision.travel = Vector3();
+ }
+ }
- on_floor = true;
- floor_velocity = collision.collider_vel;
+ if (collided) {
+ found_collision = true;
+ }
- Vector3 rel_v = lv - floor_velocity;
- Vector3 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v);
+ if (collided) {
- if (collision.travel.length() < 0.05 && hv.length() < p_slope_stop_min_velocity) {
- Transform gt = get_global_transform();
- gt.origin -= collision.travel;
- set_global_transform(gt);
- return floor_velocity - p_floor_direction * p_floor_direction.dot(floor_velocity);
- }
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
- on_ceiling = true;
- } else {
+ colliders.push_back(collision);
+ motion = collision.remainder;
+
+ bool is_on_slope = false;
+ if (p_floor_direction == Vector3()) {
+ //all is a wall
on_wall = true;
+ } else {
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
+
+ on_floor = true;
+ on_floor_body = collision.collider_rid;
+ floor_velocity = collision.collider_vel;
+
+ if (p_stop_on_slope) {
+ if (Vector3() == lv_n + p_floor_direction) {
+ Transform gt = get_global_transform();
+ gt.origin -= collision.travel;
+ set_global_transform(gt);
+ return Vector3();
+ }
+ }
+
+ is_on_slope = true;
+
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
+ }
}
- }
- Vector3 n = collision.normal;
- motion = motion.slide(n);
- lv = lv.slide(n);
+ if (p_stop_on_slope && is_on_slope) {
+ motion = motion.slide(p_floor_direction);
+ lv = lv.slide(p_floor_direction);
+ } else {
+ Vector3 n = collision.normal;
+ motion = motion.slide(n);
+ lv = lv.slide(n);
+ }
- for (int i = 0; i < 3; i++) {
- if (locked_axis & (1 << i)) {
- lv[i] = 0;
+ for (int i = 0; i < 3; i++) {
+ if (locked_axis & (1 << i)) {
+ lv[i] = 0;
+ }
}
}
- colliders.push_back(collision);
+ ++test_type;
+ } while (!p_stop_on_slope && test_type < 2);
- } else {
+ if (!found_collision || motion == Vector3())
break;
- }
- p_max_slides--;
- if (motion == Vector3())
- break;
+ --p_max_slides;
}
return lv;
}
+Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) {
+
+ bool was_on_floor = on_floor;
+
+ Vector3 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia);
+ if (!was_on_floor || p_snap == Vector3()) {
+ return ret;
+ }
+
+ Collision col;
+ Transform gt = get_global_transform();
+
+ if (move_and_collide(p_snap, p_infinite_inertia, col, true)) {
+ gt.origin += col.travel;
+ if (p_floor_direction != Vector3() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
+ on_floor = true;
+ on_floor_body = col.collider_rid;
+ floor_velocity = col.collider_vel;
+ }
+ set_global_transform(gt);
+ }
+
+ return ret;
+}
+
bool KinematicBody::is_on_floor() const {
return on_floor;
}
+
bool KinematicBody::is_on_wall() const {
return on_wall;
@@ -1081,6 +1299,43 @@ bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion,
return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
}
+bool KinematicBody::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
+
+ PhysicsServer::SeparationResult sep_res[8]; //max 8 rays
+
+ Transform gt = get_global_transform();
+
+ Vector3 recover;
+ int hits = PhysicsServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ int deepest = -1;
+ float deepest_depth;
+ for (int i = 0; i < hits; i++) {
+ if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
+ deepest = i;
+ deepest_depth = sep_res[i].collision_depth;
+ }
+ }
+
+ gt.origin += recover;
+ set_global_transform(gt);
+
+ if (deepest != -1) {
+ r_collision.collider = sep_res[deepest].collider_id;
+ r_collision.collider_metadata = sep_res[deepest].collider_metadata;
+ r_collision.collider_shape = sep_res[deepest].collider_shape;
+ r_collision.collider_vel = sep_res[deepest].collider_velocity;
+ r_collision.collision = sep_res[deepest].collision_point;
+ r_collision.normal = sep_res[deepest].collision_normal;
+ r_collision.local_shape = sep_res[deepest].collision_local_shape;
+ r_collision.travel = recover;
+ r_collision.remainder = Vector3();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) {
PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
}
@@ -1117,18 +1372,19 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
}
if (slide_colliders[p_bounce].is_null()) {
- slide_colliders[p_bounce].instance();
- slide_colliders[p_bounce]->owner = this;
+ slide_colliders.write[p_bounce].instance();
+ slide_colliders.write[p_bounce]->owner = this;
}
- slide_colliders[p_bounce]->collision = colliders[p_bounce];
+ slide_colliders.write[p_bounce]->collision = colliders[p_bounce];
return slide_colliders[p_bounce];
}
void KinematicBody::_bind_methods() {
- 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("move_and_collide", "rel_vec", "infinite_inertia", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move);
@@ -1146,13 +1402,9 @@ void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision);
- ADD_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}
@@ -1174,7 +1426,7 @@ KinematicBody::~KinematicBody() {
for (int i = 0; i < slide_colliders.size(); i++) {
if (slide_colliders[i].is_valid()) {
- slide_colliders[i]->owner = NULL;
+ slide_colliders.write[i]->owner = NULL;
}
}
}
@@ -1893,6 +2145,8 @@ void PhysicalBone::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
+ ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone::get_bone_id);
+
ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass);
ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass);
@@ -2228,6 +2482,7 @@ void PhysicalBone::set_bounce(real_t p_bounce) {
bounce = p_bounce;
PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
}
+
real_t PhysicalBone::get_bounce() const {
return bounce;
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 17d2769c79..c4db41f577 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -32,6 +32,7 @@
#define PHYSICS_BODY__H
#include "scene/3d/collision_object.h"
+#include "scene/resources/physics_material.h"
#include "servers/physics_server.h"
#include "skeleton.h"
#include "vset.h"
@@ -81,18 +82,22 @@ class StaticBody : public PhysicsBody {
Vector3 constant_linear_velocity;
Vector3 constant_angular_velocity;
- real_t bounce;
- real_t friction;
+ Ref<PhysicsMaterial> physics_material_override;
protected:
static void _bind_methods();
public:
+#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
+#endif
+
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
void set_constant_linear_velocity(const Vector3 &p_vel);
void set_constant_angular_velocity(const Vector3 &p_vel);
@@ -102,6 +107,9 @@ public:
StaticBody();
~StaticBody();
+
+private:
+ void _reload_physics_characteristics();
};
class RigidBody : public PhysicsBody {
@@ -121,9 +129,8 @@ protected:
PhysicsDirectBodyState *state;
Mode mode;
- real_t bounce;
real_t mass;
- real_t friction;
+ Ref<PhysicsMaterial> physics_material_override;
Vector3 linear_velocity;
Vector3 angular_velocity;
@@ -196,11 +203,16 @@ public:
void set_weight(real_t p_weight);
real_t get_weight() const;
+#ifndef DISABLE_DEPRECATED
void set_friction(real_t p_friction);
real_t get_friction() const;
void set_bounce(real_t p_bounce);
real_t get_bounce() const;
+#endif
+
+ void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+ Ref<PhysicsMaterial> get_physics_material_override() const;
void set_linear_velocity(const Vector3 &p_velocity);
Vector3 get_linear_velocity() const;
@@ -242,6 +254,11 @@ public:
Array get_colliding_bodies() const;
+ void add_central_force(const Vector3 &p_force);
+ void add_force(const Vector3 &p_force, const Vector3 &p_pos);
+ void add_torque(const Vector3 &p_torque);
+
+ void apply_central_impulse(const Vector3 &p_impulse);
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
void apply_torque_impulse(const Vector3 &p_impulse);
@@ -249,6 +266,9 @@ public:
RigidBody();
~RigidBody();
+
+private:
+ void _reload_physics_characteristics();
};
VARIANT_ENUM_CAST(RigidBody::Mode);
@@ -265,6 +285,7 @@ public:
Vector3 normal;
Vector3 collider_vel;
ObjectID collider;
+ RID collider_rid;
int collider_shape;
Variant collider_metadata;
Vector3 remainder;
@@ -278,6 +299,7 @@ private:
float margin;
Vector3 floor_velocity;
+ RID on_floor_body;
bool on_floor;
bool on_ceiling;
bool on_wall;
@@ -287,23 +309,26 @@ private:
_FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const;
- Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true);
+ Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_test_only = false);
Ref<KinematicCollision> _get_slide_collision(int p_bounce);
protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision);
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz, bool p_test_only = false);
bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
+ bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
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), 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));
+ Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
+ Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, 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;
@@ -537,6 +562,7 @@ protected:
private:
static Skeleton *find_skeleton_parent(Node *p_parent);
+
void _fix_joint_offset();
void _reload_joint();
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
index b2d10006f7..a30fc0ac3e 100644
--- a/scene/3d/physics_joint.cpp
+++ b/scene/3d/physics_joint.cpp
@@ -48,18 +48,14 @@ void Joint::_update_joint(bool p_only_free) {
Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;
- if (!node_a || !node_b)
- return;
-
PhysicsBody *body_a = Object::cast_to<PhysicsBody>(node_a);
PhysicsBody *body_b = Object::cast_to<PhysicsBody>(node_b);
- if (!body_a || !body_b)
- return;
-
- if (!body_a) {
+ if (!body_a && body_b)
SWAP(body_a, body_b);
- }
+
+ if (!body_a)
+ return;
joint = _configure_joint(body_a, body_b);
@@ -69,7 +65,8 @@ void Joint::_update_joint(bool p_only_free) {
PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority);
ba = body_a->get_rid();
- bb = body_b->get_rid();
+ if (body_b)
+ bb = body_b->get_rid();
PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
}
@@ -154,8 +151,8 @@ void Joint::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint::get_exclude_nodes_from_collision);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a"), "set_node_a", "get_node_a");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b"), "set_node_b", "get_node_b");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_a", "get_node_a");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_b", "get_node_b");
ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
@@ -260,7 +257,7 @@ void HingeJoint::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint::_set_lower_limit);
ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint::_get_lower_limit);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit");
@@ -270,7 +267,7 @@ void HingeJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE);
BIND_ENUM_CONSTANT(PARAM_BIAS);
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index 7f83e2c3ea..b846a5b6c0 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -208,7 +208,7 @@ void RayCast::_update_raycast_state() {
PhysicsDirectSpaceState::RayResult rr;
- if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask)) {
+ if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
collided = true;
against = rr.collider_id;
@@ -259,6 +259,26 @@ void RayCast::clear_exceptions() {
exclude.clear();
}
+void RayCast::set_collide_with_areas(bool p_clip) {
+
+ collide_with_areas = p_clip;
+}
+
+bool RayCast::is_collide_with_areas_enabled() const {
+
+ return collide_with_areas;
+}
+
+void RayCast::set_collide_with_bodies(bool p_clip) {
+
+ collide_with_bodies = p_clip;
+}
+
+bool RayCast::is_collide_with_bodies_enabled() const {
+
+ return collide_with_bodies;
+}
+
void RayCast::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast::set_enabled);
@@ -292,10 +312,20 @@ void RayCast::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast::get_exclude_parent_body);
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast::is_collide_with_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast::is_collide_with_bodies_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Collide With", "collide_with");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
}
void RayCast::_create_debug_shape() {
@@ -370,4 +400,6 @@ RayCast::RayCast() {
cast_to = Vector3(0, -1, 0);
debug_shape = NULL;
exclude_parent_body = true;
+ collide_with_areas = false;
+ collide_with_bodies = true;
}
diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h
index 20cea80700..e95382e1fe 100644
--- a/scene/3d/ray_cast.h
+++ b/scene/3d/ray_cast.h
@@ -45,7 +45,6 @@ class RayCast : public Spatial {
Vector3 collision_normal;
Vector3 cast_to;
-
Set<RID> exclude;
uint32_t collision_mask;
@@ -58,12 +57,21 @@ class RayCast : public Spatial {
void _update_debug_shape();
void _clear_debug_shape();
+ bool collide_with_areas;
+ bool collide_with_bodies;
+
protected:
void _notification(int p_what);
void _update_raycast_state();
static void _bind_methods();
public:
+ void set_collide_with_areas(bool p_clip);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_collide_with_bodies(bool p_clip);
+ bool is_collide_with_bodies_enabled() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 4d50945062..fe522bbe97 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -274,6 +274,7 @@ ReflectionProbe::ReflectionProbe() {
probe = VisualServer::get_singleton()->reflection_probe_create();
VS::get_singleton()->instance_set_base(get_instance(), probe);
+ set_disable_scale(true);
}
ReflectionProbe::~ReflectionProbe() {
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
index afb85f7314..c12e49fb47 100644
--- a/scene/3d/remote_transform.cpp
+++ b/scene/3d/remote_transform.cpp
@@ -124,8 +124,10 @@ void RemoteTransform::_notification(int p_what) {
void RemoteTransform::set_remote_node(const NodePath &p_remote_node) {
remote_node = p_remote_node;
- if (is_inside_tree())
+ if (is_inside_tree()) {
_update_cache();
+ _update_remote();
+ }
update_configuration_warning();
}
@@ -194,7 +196,7 @@ void RemoteTransform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale);
ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path"), "set_remote_node", "get_remote_node");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");
ADD_GROUP("Update", "update_");
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 76d90dc6ff..c796e47f25 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -66,7 +66,7 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
Array children = p_value;
if (is_inside_tree()) {
- bones[which].nodes_bound.clear();
+ bones.write[which].nodes_bound.clear();
for (int i = 0; i < children.size(); i++) {
@@ -131,7 +131,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
String prep = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
- p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(i - 1) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
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));
@@ -139,6 +139,59 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+void Skeleton::_update_process_order() {
+
+ if (!process_order_dirty)
+ return;
+
+ Bone *bonesptr = bones.ptrw();
+ int len = bones.size();
+
+ process_order.resize(len);
+ int *order = process_order.ptrw();
+ for (int i = 0; i < len; i++) {
+
+ if (bonesptr[i].parent >= len) {
+ //validate this just in case
+ ERR_PRINTS("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
+ bonesptr[i].parent = -1;
+ }
+ order[i] = i;
+ bonesptr[i].sort_index = i;
+ }
+ //now check process order
+ int pass_count = 0;
+ while (pass_count < len * len) {
+ //using bubblesort because of simplicity, it wont run every frame though.
+ //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic
+ bool swapped = false;
+ for (int i = 0; i < len; i++) {
+ int parent_idx = bonesptr[order[i]].parent;
+ if (parent_idx < 0)
+ continue; //do nothing because it has no parent
+ //swap indices
+ int parent_order = bonesptr[parent_idx].sort_index;
+ if (parent_order > i) {
+ bonesptr[order[i]].sort_index = parent_order;
+ bonesptr[parent_idx].sort_index = i;
+ //swap order
+ SWAP(order[i], order[parent_order]);
+ swapped = true;
+ }
+ }
+
+ if (!swapped)
+ break;
+ pass_count++;
+ }
+
+ if (pass_count == len * len) {
+ ERR_PRINT("Skeleton parenthood graph is cyclic");
+ }
+
+ process_order_dirty = false;
+}
+
void Skeleton::_notification(int p_what) {
switch (p_what) {
@@ -176,24 +229,28 @@ void Skeleton::_notification(int p_what) {
case NOTIFICATION_UPDATE_SKELETON: {
VisualServer *vs = VisualServer::get_singleton();
- Bone *bonesptr = &bones[0];
+ Bone *bonesptr = bones.ptrw();
int len = bones.size();
vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens
+ _update_process_order();
+
+ const int *order = process_order.ptr();
+
// pose changed, rebuild cache of inverses
if (rest_global_inverse_dirty) {
// calculate global rests and invert them
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
if (b.parent >= 0)
b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest;
else
b.rest_global_inverse = b.rest;
}
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
b.rest_global_inverse.affine_invert();
}
@@ -205,7 +262,7 @@ void Skeleton::_notification(int p_what) {
for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[i];
+ Bone &b = bonesptr[order[i]];
if (b.disable_rest) {
if (b.enabled) {
@@ -319,12 +376,13 @@ void Skeleton::add_bone(const String &p_name) {
for (int i = 0; i < bones.size(); i++) {
- ERR_FAIL_COND(bones[i].name == "p_name");
+ ERR_FAIL_COND(bones[i].name == p_name);
}
Bone b;
b.name = p_name;
bones.push_back(b);
+ process_order_dirty = true;
rest_global_inverse_dirty = true;
_make_dirty();
@@ -368,10 +426,11 @@ int Skeleton::get_bone_count() const {
void Skeleton::set_bone_parent(int p_bone, int p_parent) {
ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(p_parent != -1 && (p_parent < 0 || p_parent >= p_bone));
+ ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
- bones[p_bone].parent = p_parent;
+ bones.write[p_bone].parent = p_parent;
rest_global_inverse_dirty = true;
+ process_order_dirty = true;
_make_dirty();
}
@@ -379,21 +438,24 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
ERR_FAIL_INDEX(p_bone, bones.size());
+ _update_process_order();
+
int parent = bones[p_bone].parent;
while (parent >= 0) {
- bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
+ bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
parent = bones[parent].parent;
}
- bones[p_bone].parent = -1;
- bones[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
+ bones.write[p_bone].parent = -1;
+ bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
+ process_order_dirty = true;
_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;
+ bones.write[p_bone].ignore_animation = p_ignore;
}
bool Skeleton::is_bone_ignore_animation(int p_bone) const {
@@ -405,7 +467,7 @@ bool Skeleton::is_bone_ignore_animation(int p_bone) const {
void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].disable_rest = p_disable;
+ bones.write[p_bone].disable_rest = p_disable;
}
bool Skeleton::is_bone_rest_disabled(int p_bone) const {
@@ -425,7 +487,7 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].rest = p_rest;
+ bones.write[p_bone].rest = p_rest;
rest_global_inverse_dirty = true;
_make_dirty();
}
@@ -440,7 +502,7 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) {
ERR_FAIL_INDEX(p_bone, bones.size());
- bones[p_bone].enabled = p_enabled;
+ bones.write[p_bone].enabled = p_enabled;
rest_global_inverse_dirty = true;
_make_dirty();
}
@@ -457,13 +519,13 @@ void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) {
uint32_t id = p_node->get_instance_id();
- for (List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
+ for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) {
if (E->get() == id)
return; // already here
}
- bones[p_bone].nodes_bound.push_back(id);
+ bones.write[p_bone].nodes_bound.push_back(id);
}
void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) {
@@ -471,7 +533,7 @@ void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) {
ERR_FAIL_INDEX(p_bone, bones.size());
uint32_t id = p_node->get_instance_id();
- bones[p_bone].nodes_bound.erase(id);
+ bones.write[p_bone].nodes_bound.erase(id);
}
void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const {
@@ -489,6 +551,8 @@ void Skeleton::clear_bones() {
bones.clear();
rest_global_inverse_dirty = true;
+ process_order_dirty = true;
+
_make_dirty();
}
@@ -499,7 +563,7 @@ void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
ERR_FAIL_COND(!is_inside_tree());
- bones[p_bone].pose = p_pose;
+ bones.write[p_bone].pose = p_pose;
_make_dirty();
}
Transform Skeleton::get_bone_pose(int p_bone) const {
@@ -513,8 +577,8 @@ void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose)
ERR_FAIL_INDEX(p_bone, bones.size());
//ERR_FAIL_COND( !is_inside_scene() );
- bones[p_bone].custom_pose_enable = (p_custom_pose != Transform());
- bones[p_bone].custom_pose = p_custom_pose;
+ bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform());
+ bones.write[p_bone].custom_pose = p_custom_pose;
_make_dirty();
}
@@ -538,27 +602,38 @@ void Skeleton::_make_dirty() {
dirty = true;
}
+int Skeleton::get_process_order(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx, bones.size(), -1);
+ _update_process_order();
+ return process_order[p_idx];
+}
+
void Skeleton::localize_rests() {
- for (int i = bones.size() - 1; i >= 0; i--) {
+ _update_process_order();
- if (bones[i].parent >= 0)
- set_bone_rest(i, bones[bones[i].parent].rest.affine_inverse() * bones[i].rest);
+ for (int i = bones.size() - 1; i >= 0; i--) {
+ int idx = process_order[i];
+ if (bones[idx].parent >= 0) {
+ set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest);
+ }
}
}
+#ifndef _3D_DISABLED
+
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;
+ bones.write[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;
+ bones.write[p_bone].physical_bone = NULL;
_rebuild_physical_bones_cache();
}
@@ -598,9 +673,12 @@ PhysicalBone *Skeleton::_get_physical_bone_parent(int p_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();
+ PhysicalBone *parent_pb = _get_physical_bone_parent(i);
+ if (parent_pb != bones[i].physical_bone) {
+ bones.write[i].cache_parent_physical_bone = parent_pb;
+ if (bones[i].physical_bone)
+ bones[i].physical_bone->_on_bone_parent_changed();
+ }
}
}
@@ -658,7 +736,7 @@ void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
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.write[c++] = bone_id;
}
}
sim_bones.resize(c);
@@ -691,6 +769,8 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
_physical_bones_add_remove_collision_exception(false, this, p_exception);
}
+#endif // _3D_DISABLED
+
void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
@@ -727,11 +807,17 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
+#ifndef _3D_DISABLED
+
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);
+#endif // _3D_DISABLED
+
+ ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation);
+
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@@ -739,6 +825,7 @@ Skeleton::Skeleton() {
rest_global_inverse_dirty = true;
dirty = false;
+ process_order_dirty = true;
skeleton = VisualServer::get_singleton()->skeleton_create();
set_notify_transform(true);
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index dad11960a5..e044e08437 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -38,7 +38,12 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
+#ifndef _3D_DISABLED
+typedef int BoneId;
+
class PhysicalBone;
+#endif // _3D_DISABLED
+
class Skeleton : public Spatial {
GDCLASS(Skeleton, Spatial);
@@ -49,6 +54,7 @@ class Skeleton : public Spatial {
bool enabled;
int parent;
+ int sort_index; //used for re-sorting process order
bool ignore_animation;
@@ -64,8 +70,10 @@ class Skeleton : public Spatial {
Transform transform_final;
+#ifndef _3D_DISABLED
PhysicalBone *physical_bone;
PhysicalBone *cache_parent_physical_bone;
+#endif // _3D_DISABLED
List<uint32_t> nodes_bound;
@@ -75,21 +83,25 @@ class Skeleton : public Spatial {
ignore_animation = false;
custom_pose_enable = false;
disable_rest = false;
+#ifndef _3D_DISABLED
physical_bone = NULL;
cache_parent_physical_bone = NULL;
+#endif // _3D_DISABLED
}
};
bool rest_global_inverse_dirty;
Vector<Bone> bones;
+ Vector<int> process_order;
+ bool process_order_dirty;
RID skeleton;
void _make_dirty();
bool dirty;
- //bind helpers
+ // bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const {
Array bound;
@@ -103,6 +115,8 @@ class Skeleton : public Spatial {
return bound;
}
+ void _update_process_order();
+
protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
@@ -163,7 +177,9 @@ public:
Transform get_bone_custom_pose(int p_bone) const;
void localize_rests(); // used for loaders and tools
+ int get_process_order(int p_idx);
+#ifndef _3D_DISABLED
// Physical bone API
void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
@@ -182,6 +198,7 @@ public:
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);
+#endif // _3D_DISABLED
public:
Skeleton();
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
new file mode 100644
index 0000000000..58ddb52760
--- /dev/null
+++ b/scene/3d/soft_body.cpp
@@ -0,0 +1,798 @@
+/*************************************************************************/
+/* soft_body.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 "soft_body.h"
+#include "os/os.h"
+#include "scene/3d/collision_object.h"
+#include "scene/3d/skeleton.h"
+#include "servers/physics_server.h"
+
+SoftBodyVisualServerHandler::SoftBodyVisualServerHandler() {}
+
+void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) {
+ clear();
+
+ ERR_FAIL_COND(!p_mesh.is_valid());
+
+ mesh = p_mesh;
+ surface = p_surface;
+
+ const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, surface);
+ const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface);
+ const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface);
+ uint32_t surface_offsets[VS::ARRAY_MAX];
+
+ buffer = VS::get_singleton()->mesh_surface_get_array(mesh, surface);
+ stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets);
+ offset_vertices = surface_offsets[VS::ARRAY_VERTEX];
+ offset_normal = surface_offsets[VS::ARRAY_NORMAL];
+}
+
+void SoftBodyVisualServerHandler::clear() {
+
+ if (mesh.is_valid()) {
+ buffer.resize(0);
+ }
+
+ mesh = RID();
+}
+
+void SoftBodyVisualServerHandler::open() {
+ write_buffer = buffer.write();
+}
+
+void SoftBodyVisualServerHandler::close() {
+ write_buffer = PoolVector<uint8_t>::Write();
+}
+
+void SoftBodyVisualServerHandler::commit_changes() {
+ VS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer);
+}
+
+void SoftBodyVisualServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
+ copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+}
+
+void SoftBodyVisualServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
+ copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+}
+
+void SoftBodyVisualServerHandler::set_aabb(const AABB &p_aabb) {
+ VS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
+}
+
+SoftBody::PinnedPoint::PinnedPoint() :
+ point_index(-1),
+ spatial_attachment(NULL) {
+}
+
+SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
+ point_index = obj_tocopy.point_index;
+ spatial_attachment_path = obj_tocopy.spatial_attachment_path;
+ spatial_attachment = obj_tocopy.spatial_attachment;
+ offset = obj_tocopy.offset;
+}
+
+void SoftBody::_update_pickable() {
+ if (!is_inside_tree())
+ return;
+ bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree();
+ PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
+}
+
+bool SoftBody::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ String which = name.get_slicec('/', 0);
+
+ if ("pinned_points" == which) {
+
+ return _set_property_pinned_points_indices(p_value);
+
+ } else if ("attachments" == which) {
+
+ int idx = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+
+ return _set_property_pinned_points_attachment(idx, what, p_value);
+ }
+
+ return false;
+}
+
+bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const {
+ String name = p_name;
+ String which = name.get_slicec('/', 0);
+
+ if ("pinned_points" == which) {
+ Array arr_ret;
+ const int pinned_points_indices_size = pinned_points.size();
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ arr_ret.resize(pinned_points_indices_size);
+
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ arr_ret[i] = r[i].point_index;
+ }
+
+ r_ret = arr_ret;
+ return true;
+
+ } else if ("attachments" == which) {
+
+ int idx = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+
+ return _get_property_pinned_points(idx, what, r_ret);
+ }
+
+ return false;
+}
+
+void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ const int pinned_points_indices_size = pinned_points.size();
+
+ p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points"));
+
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index"));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset"));
+ }
+}
+
+bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) {
+
+ const int p_indices_size = p_indices.size();
+
+ { // Remove the pined points on physics server that will be removed by resize
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ if (p_indices_size < pinned_points.size()) {
+ for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) {
+ pin_point(r[i].point_index, false);
+ }
+ }
+ }
+
+ pinned_points.resize(p_indices_size);
+
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ int point_index;
+ for (int i = 0; i < p_indices_size; ++i) {
+ point_index = p_indices.get(i);
+ if (w[i].point_index != point_index) {
+ if (-1 != w[i].point_index)
+ pin_point(w[i].point_index, false);
+ w[i].point_index = point_index;
+ pin_point(w[i].point_index, true);
+ }
+ }
+ return true;
+}
+
+bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
+ if (pinned_points.size() <= p_item) {
+ return false;
+ }
+
+ if ("spatial_attachment_path" == p_what) {
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ pin_point(w[p_item].point_index, true, p_value);
+ _make_cache_dirty();
+ } else if ("offset" == p_what) {
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ w[p_item].offset = p_value;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
+ if (pinned_points.size() <= p_item) {
+ return false;
+ }
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+
+ if ("point_index" == p_what) {
+ r_ret = r[p_item].point_index;
+ } else if ("spatial_attachment_path" == p_what) {
+ r_ret = r[p_item].spatial_attachment_path;
+ } else if ("offset" == p_what) {
+ r_ret = r[p_item].offset;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) {
+ update_physics_server();
+ _reset_points_offsets();
+#ifdef TOOLS_ENABLED
+ if (p_changed == this) {
+ update_configuration_warning();
+ }
+#endif
+}
+
+void SoftBody::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_WORLD: {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ add_change_receptor(this);
+ }
+
+ RID space = get_world()->get_space();
+ PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space);
+ update_physics_server();
+ } break;
+ case NOTIFICATION_READY: {
+ if (!parent_collision_ignore.is_empty())
+ add_collision_exception_with(get_node(parent_collision_ignore));
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ _reset_points_offsets();
+ return;
+ }
+
+ PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform());
+
+ set_notify_transform(false);
+ // Required to be top level with Transform at center of world in order to modify VisualServer only to support custom Transform
+ set_as_toplevel(true);
+ set_transform(Transform());
+ set_notify_transform(true);
+
+ } break;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+
+ if (!simulation_started)
+ return;
+
+ _update_cache_pin_points_datas();
+ // Submit bone attachment
+ const int pinned_points_indices_size = pinned_points.size();
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ for (int i = 0; i < pinned_points_indices_size; ++i) {
+ if (r[i].spatial_attachment) {
+ PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset));
+ }
+ }
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ _update_pickable();
+
+ } break;
+ case NOTIFICATION_EXIT_WORLD: {
+
+ PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, RID());
+
+ } break;
+ }
+
+#ifdef TOOLS_ENABLED
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warning();
+ }
+ }
+
+#endif
+}
+
+void SoftBody::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_draw_soft_mesh"), &SoftBody::_draw_soft_mesh);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody::get_collision_layer);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody::get_collision_layer_bit);
+
+ ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore);
+
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with);
+
+ ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody::set_simulation_precision);
+ ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody::get_simulation_precision);
+
+ ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody::set_total_mass);
+ ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody::get_total_mass);
+
+ ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody::set_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody::get_linear_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody::set_areaAngular_stiffness);
+ ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody::get_areaAngular_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody::set_volume_stiffness);
+ ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody::get_volume_stiffness);
+
+ ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody::set_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody::get_pressure_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody::set_pose_matching_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody::get_pose_matching_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody::set_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody::get_damping_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody::set_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody::get_drag_coefficient);
+
+ ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody::set_ray_pickable);
+ ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody::is_ray_pickable);
+
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient");
+}
+
+String SoftBody::get_configuration_warning() const {
+
+ String warning = MeshInstance::get_configuration_warning();
+
+ if (get_mesh().is_null()) {
+ if (!warning.empty())
+ warning += "\n\n";
+
+ warning += TTR("This body will be ignored until you set a mesh");
+ }
+
+ Transform t = get_transform();
+ if ((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 (!warning.empty())
+ warning += "\n\n";
+
+ warning += TTR("Size changes to SoftBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ }
+
+ return warning;
+}
+
+void SoftBody::_draw_soft_mesh() {
+ if (get_mesh().is_null())
+ return;
+
+ if (!visual_server_handler.is_ready()) {
+
+ visual_server_handler.prepare(get_mesh()->get_rid(), 0);
+
+ /// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
+ simulation_started = true;
+ call_deferred("set_as_toplevel", true);
+ call_deferred("set_transform", Transform());
+ }
+
+ visual_server_handler.open();
+ PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler);
+ visual_server_handler.close();
+
+ visual_server_handler.commit_changes();
+}
+
+void SoftBody::update_physics_server() {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ if (get_mesh().is_valid())
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ else
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
+
+ return;
+ }
+
+ if (get_mesh().is_valid()) {
+
+ become_mesh_owner();
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh());
+ VS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh");
+ } else {
+
+ PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ }
+}
+
+void SoftBody::become_mesh_owner() {
+ if (mesh.is_null())
+ return;
+
+ if (!mesh_owner) {
+ mesh_owner = true;
+
+ Vector<Ref<Material> > copy_materials;
+ copy_materials.append_array(materials);
+
+ ERR_FAIL_COND(!mesh->get_surface_count());
+
+ // Get current mesh array and create new mesh array with necessary flag for softbody
+ Array surface_arrays = mesh->surface_get_arrays(0);
+ Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
+ uint32_t surface_format = mesh->surface_get_format(0);
+
+ surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL);
+ surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
+
+ Ref<ArrayMesh> soft_mesh;
+ soft_mesh.instance();
+ soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format);
+ soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
+
+ set_mesh(soft_mesh);
+
+ for (int i = copy_materials.size() - 1; 0 <= i; --i) {
+ set_surface_material(i, copy_materials[i]);
+ }
+ }
+}
+
+void SoftBody::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ PhysicsServer::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
+}
+
+uint32_t SoftBody::get_collision_mask() const {
+ return collision_mask;
+}
+void SoftBody::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ PhysicsServer::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
+}
+
+uint32_t SoftBody::get_collision_layer() const {
+ return collision_layer;
+}
+
+void SoftBody::set_collision_mask_bit(int p_bit, bool p_value) {
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask |= 1 << p_bit;
+ else
+ mask &= ~(1 << p_bit);
+ set_collision_mask(mask);
+}
+
+bool SoftBody::get_collision_mask_bit(int p_bit) const {
+ return get_collision_mask() & (1 << p_bit);
+}
+
+void SoftBody::set_collision_layer_bit(int p_bit, bool p_value) {
+ uint32_t layer = get_collision_layer();
+ if (p_value)
+ layer |= 1 << p_bit;
+ else
+ layer &= ~(1 << p_bit);
+ set_collision_layer(layer);
+}
+
+bool SoftBody::get_collision_layer_bit(int p_bit) const {
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void SoftBody::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+ parent_collision_ignore = p_parent_collision_ignore;
+}
+
+const NodePath &SoftBody::get_parent_collision_ignore() const {
+ return parent_collision_ignore;
+}
+
+void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) {
+ pinned_points = p_pinned_points_indices;
+ PoolVector<PinnedPoint>::Read w = pinned_points.read();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+ pin_point(p_pinned_points_indices[i].point_index, true);
+ }
+}
+
+PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() {
+ return pinned_points;
+}
+
+void SoftBody::add_collision_exception_with(Node *p_node) {
+ ERR_FAIL_NULL(p_node);
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
+ }
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
+}
+
+void SoftBody::remove_collision_exception_with(Node *p_node) {
+ ERR_FAIL_NULL(p_node);
+ CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node);
+ if (!collision_object) {
+ ERR_EXPLAIN("Collision exception only works between two CollisionObject");
+ }
+ ERR_FAIL_COND(!collision_object);
+ PhysicsServer::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
+}
+
+int SoftBody::get_simulation_precision() {
+ return PhysicsServer::get_singleton()->soft_body_get_simulation_precision(physics_rid);
+}
+
+void SoftBody::set_simulation_precision(int p_simulation_precision) {
+ PhysicsServer::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
+}
+
+real_t SoftBody::get_total_mass() {
+ return PhysicsServer::get_singleton()->soft_body_get_total_mass(physics_rid);
+}
+
+void SoftBody::set_total_mass(real_t p_total_mass) {
+ PhysicsServer::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
+}
+
+void SoftBody::set_linear_stiffness(real_t p_linear_stiffness) {
+ PhysicsServer::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
+}
+
+real_t SoftBody::get_linear_stiffness() {
+ return PhysicsServer::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
+}
+
+void SoftBody::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) {
+ PhysicsServer::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness);
+}
+
+real_t SoftBody::get_areaAngular_stiffness() {
+ return PhysicsServer::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid);
+}
+
+void SoftBody::set_volume_stiffness(real_t p_volume_stiffness) {
+ PhysicsServer::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness);
+}
+
+real_t SoftBody::get_volume_stiffness() {
+ return PhysicsServer::get_singleton()->soft_body_get_volume_stiffness(physics_rid);
+}
+
+real_t SoftBody::get_pressure_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
+}
+
+void SoftBody::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient);
+}
+
+real_t SoftBody::get_pose_matching_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid);
+}
+
+void SoftBody::set_pressure_coefficient(real_t p_pressure_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
+}
+
+real_t SoftBody::get_damping_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
+}
+
+void SoftBody::set_damping_coefficient(real_t p_damping_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
+}
+
+real_t SoftBody::get_drag_coefficient() {
+ return PhysicsServer::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
+}
+
+void SoftBody::set_drag_coefficient(real_t p_drag_coefficient) {
+ PhysicsServer::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
+}
+
+Vector3 SoftBody::get_point_transform(int p_point_index) {
+ return PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
+}
+
+void SoftBody::pin_point_toggle(int p_point_index) {
+ pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
+}
+
+void SoftBody::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
+ _pin_point_on_physics_server(p_point_index, pin);
+ if (pin) {
+ _add_pinned_point(p_point_index, p_spatial_attachment_path);
+ } else {
+ _remove_pinned_point(p_point_index);
+ }
+}
+
+bool SoftBody::is_point_pinned(int p_point_index) const {
+ return -1 != _has_pinned_point(p_point_index);
+}
+
+void SoftBody::set_ray_pickable(bool p_ray_pickable) {
+
+ ray_pickable = p_ray_pickable;
+ _update_pickable();
+}
+
+bool SoftBody::is_ray_pickable() const {
+
+ return ray_pickable;
+}
+
+SoftBody::SoftBody() :
+ MeshInstance(),
+ physics_rid(PhysicsServer::get_singleton()->soft_body_create()),
+ mesh_owner(false),
+ collision_mask(1),
+ collision_layer(1),
+ simulation_started(false),
+ pinned_points_cache_dirty(true) {
+
+ PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
+ //set_notify_transform(true);
+ set_physics_process_internal(true);
+}
+
+SoftBody::~SoftBody() {
+}
+
+void SoftBody::reset_softbody_pin() {
+ PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid);
+ PoolVector<PinnedPoint>::Read pps = pinned_points.read();
+ for (int i = pinned_points.size() - 1; 0 < i; --i) {
+ PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true);
+ }
+}
+
+void SoftBody::_make_cache_dirty() {
+ pinned_points_cache_dirty = true;
+}
+
+void SoftBody::_update_cache_pin_points_datas() {
+ if (!pinned_points_cache_dirty)
+ return;
+
+ pinned_points_cache_dirty = false;
+
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+
+ if (!w[i].spatial_attachment_path.is_empty()) {
+ w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path));
+ }
+ if (!w[i].spatial_attachment) {
+ ERR_PRINT("Spatial node not defined in the pinned point, Softbody undefined behaviour!");
+ }
+ }
+}
+
+void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) {
+ PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
+}
+
+void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
+ SoftBody::PinnedPoint *pinned_point;
+ if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
+
+ // Create new
+ PinnedPoint pp;
+ pp.point_index = p_point_index;
+ pp.spatial_attachment_path = p_spatial_attachment_path;
+
+ if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
+ pp.spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
+ pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index));
+ }
+
+ pinned_points.push_back(pp);
+
+ } else {
+
+ pinned_point->point_index = p_point_index;
+ pinned_point->spatial_attachment_path = p_spatial_attachment_path;
+
+ if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
+ pinned_point->spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path));
+ pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index));
+ }
+ }
+}
+
+void SoftBody::_reset_points_offsets() {
+
+ if (!Engine::get_singleton()->is_editor_hint())
+ return;
+
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ PoolVector<PinnedPoint>::Write w = pinned_points.write();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+
+ if (!r[i].spatial_attachment)
+ w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(r[i].spatial_attachment_path));
+
+ if (!r[i].spatial_attachment)
+ continue;
+
+ w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index));
+ }
+}
+
+void SoftBody::_remove_pinned_point(int p_point_index) {
+ const int id(_has_pinned_point(p_point_index));
+ if (-1 != id) {
+ pinned_points.remove(id);
+ }
+}
+
+int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_point) const {
+ const int id = _has_pinned_point(p_point_index);
+ if (-1 == id) {
+ r_point = NULL;
+ return -1;
+ } else {
+ r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.read()[id]);
+ return id;
+ }
+}
+
+int SoftBody::_has_pinned_point(int p_point_index) const {
+ PoolVector<PinnedPoint>::Read r = pinned_points.read();
+ for (int i = pinned_points.size() - 1; 0 <= i; --i) {
+ if (p_point_index == r[i].point_index) {
+ return i;
+ }
+ }
+ return -1;
+}
diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h
new file mode 100644
index 0000000000..ee3d8d87cf
--- /dev/null
+++ b/scene/3d/soft_body.h
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* soft_body.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 SOFT_PHYSICS_BODY_H
+#define SOFT_PHYSICS_BODY_H
+
+#include "scene/3d/mesh_instance.h"
+
+class SoftBody;
+
+class SoftBodyVisualServerHandler {
+
+ friend class SoftBody;
+
+ RID mesh;
+ int surface;
+ PoolVector<uint8_t> buffer;
+ uint32_t stride;
+ uint32_t offset_vertices;
+ uint32_t offset_normal;
+
+ PoolVector<uint8_t>::Write write_buffer;
+
+private:
+ SoftBodyVisualServerHandler();
+ bool is_ready() { return mesh.is_valid(); }
+ void prepare(RID p_mesh_rid, int p_surface);
+ void clear();
+ void open();
+ void close();
+ void commit_changes();
+
+public:
+ void set_vertex(int p_vertex_id, const void *p_vector3);
+ void set_normal(int p_vertex_id, const void *p_vector3);
+ void set_aabb(const AABB &p_aabb);
+};
+
+class SoftBody : public MeshInstance {
+ GDCLASS(SoftBody, MeshInstance);
+
+public:
+ struct PinnedPoint {
+ int point_index;
+ NodePath spatial_attachment_path;
+ Spatial *spatial_attachment; // Cache
+ Vector3 offset;
+
+ PinnedPoint();
+ PinnedPoint(const PinnedPoint &obj_tocopy);
+ };
+
+private:
+ SoftBodyVisualServerHandler visual_server_handler;
+
+ RID physics_rid;
+
+ bool mesh_owner;
+ uint32_t collision_mask;
+ uint32_t collision_layer;
+ NodePath parent_collision_ignore;
+ PoolVector<PinnedPoint> pinned_points;
+ bool simulation_started;
+ bool pinned_points_cache_dirty;
+
+ Ref<ArrayMesh> debug_mesh_cache;
+ class MeshInstance *debug_mesh;
+
+ bool capture_input_on_drag;
+ bool ray_pickable;
+
+ void _update_pickable();
+
+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;
+
+ bool _set_property_pinned_points_indices(const Array &p_indices);
+ bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value);
+ bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const;
+
+ virtual void _changed_callback(Object *p_changed, const char *p_prop);
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ virtual String get_configuration_warning() const;
+
+protected:
+ void _draw_soft_mesh();
+
+public:
+ void update_physics_server();
+ void become_mesh_owner();
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
+ void set_collision_layer_bit(int p_bit, bool p_value);
+ bool get_collision_layer_bit(int p_bit) const;
+
+ void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
+ const NodePath &get_parent_collision_ignore() const;
+
+ void set_pinned_points_indices(PoolVector<PinnedPoint> p_pinned_points_indices);
+ PoolVector<PinnedPoint> get_pinned_points_indices();
+
+ void set_simulation_precision(int p_simulation_precision);
+ int get_simulation_precision();
+
+ void set_total_mass(real_t p_total_mass);
+ real_t get_total_mass();
+
+ void set_linear_stiffness(real_t p_linear_stiffness);
+ real_t get_linear_stiffness();
+
+ void set_areaAngular_stiffness(real_t p_areaAngular_stiffness);
+ real_t get_areaAngular_stiffness();
+
+ void set_volume_stiffness(real_t p_volume_stiffness);
+ real_t get_volume_stiffness();
+
+ void set_pressure_coefficient(real_t p_pressure_coefficient);
+ real_t get_pressure_coefficient();
+
+ void set_pose_matching_coefficient(real_t p_pose_matching_coefficient);
+ real_t get_pose_matching_coefficient();
+
+ void set_damping_coefficient(real_t p_damping_coefficient);
+ real_t get_damping_coefficient();
+
+ void set_drag_coefficient(real_t p_drag_coefficient);
+ real_t get_drag_coefficient();
+
+ void add_collision_exception_with(Node *p_node);
+ void remove_collision_exception_with(Node *p_node);
+
+ Vector3 get_point_transform(int p_point_index);
+
+ void pin_point_toggle(int p_point_index);
+ void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
+ bool is_point_pinned(int p_point_index) const;
+
+ void set_ray_pickable(bool p_ray_pickable);
+ bool is_ray_pickable() const;
+
+ SoftBody();
+ ~SoftBody();
+
+private:
+ void reset_softbody_pin();
+
+ void _make_cache_dirty();
+ void _update_cache_pin_points_datas();
+
+ void _pin_point_on_physics_server(int p_point_index, bool pin);
+ void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path);
+ void _reset_points_offsets();
+
+ void _remove_pinned_point(int p_point_index);
+ int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const;
+ int _has_pinned_point(int p_point_index) const;
+};
+
+#endif // SOFT_PHYSICS_BODY_H
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index 748aa8aad4..d52f634639 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -185,10 +185,8 @@ void Spatial::_notification(int p_what) {
if (data.gizmo.is_valid()) {
data.gizmo->create();
- if (data.gizmo->can_draw()) {
- if (is_visible_in_tree()) {
- data.gizmo->redraw();
- }
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
}
data.gizmo->transform();
}
@@ -202,6 +200,7 @@ void Spatial::_notification(int p_what) {
#ifdef TOOLS_ENABLED
if (data.gizmo.is_valid()) {
data.gizmo->free();
+ data.gizmo.unref();
}
#endif
@@ -280,6 +279,10 @@ Transform Spatial::get_global_transform() const {
data.global_transform = data.local_transform;
}
+ if (data.disable_scale) {
+ data.global_transform.basis.orthonormalize();
+ }
+
data.dirty &= ~DIRTY_GLOBAL;
}
@@ -418,10 +421,8 @@ void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {
if (data.gizmo.is_valid() && is_inside_world()) {
data.gizmo->create();
- if (data.gizmo->can_draw()) {
- if (is_visible_in_tree()) {
- data.gizmo->redraw();
- }
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
}
data.gizmo->transform();
}
@@ -447,12 +448,10 @@ void Spatial::_update_gizmo() {
return;
data.gizmo_dirty = false;
if (data.gizmo.is_valid()) {
- if (data.gizmo->can_draw()) {
- if (is_visible_in_tree())
- data.gizmo->redraw();
- else
- data.gizmo->clear();
- }
+ if (is_visible_in_tree())
+ data.gizmo->redraw();
+ else
+ data.gizmo->clear();
}
#endif
}
@@ -467,6 +466,15 @@ void Spatial::set_disable_gizmo(bool p_enabled) {
#endif
+void Spatial::set_disable_scale(bool p_enabled) {
+
+ data.disable_scale = p_enabled;
+}
+
+bool Spatial::is_scale_disabled() const {
+ return data.disable_scale;
+}
+
void Spatial::set_as_toplevel(bool p_enabled) {
if (data.toplevel == p_enabled)
@@ -632,19 +640,15 @@ void Spatial::scale_object_local(const Vector3 &p_scale) {
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;
+ t.basis.rotate(p_axis, p_angle);
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;
+ t.basis.scale(p_scale);
set_global_transform(t);
}
@@ -735,6 +739,8 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification);
ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel);
ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
+ ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Spatial::set_disable_scale);
+ ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Spatial::is_scale_disabled);
ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world);
ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
@@ -755,15 +761,6 @@ 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_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_axis, float p_angle);
- void global_translate(const Vector3 &p_offset);
-
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);
@@ -791,12 +788,13 @@ void Spatial::_bind_methods() {
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ;
ADD_GROUP("Transform", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
+ ADD_GROUP("Matrix", "");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
ADD_GROUP("Visibility", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
@@ -817,6 +815,7 @@ Spatial::Spatial() :
data.viewport = NULL;
data.inside_world = false;
data.visible = true;
+ data.disable_scale = false;
#ifdef TOOLS_ENABLED
data.gizmo_disabled = false;
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index a43bed3e4a..8d3c32d116 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -48,9 +48,9 @@ public:
virtual void clear() = 0;
virtual void redraw() = 0;
virtual void free() = 0;
- virtual bool can_draw() const = 0;
SpatialGizmo();
+ virtual ~SpatialGizmo() {}
};
class Spatial : public Node {
@@ -92,6 +92,7 @@ class Spatial : public Node {
bool notify_transform;
bool visible;
+ bool disable_scale;
#ifdef TOOLS_ENABLED
Ref<SpatialGizmo> gizmo;
@@ -153,6 +154,9 @@ public:
void set_as_toplevel(bool p_enabled);
bool is_set_as_toplevel() const;
+ void set_disable_scale(bool p_enabled);
+ bool is_scale_disabled() const;
+
void set_disable_gizmo(bool p_enabled);
void update_gizmo();
void set_gizmo(const Ref<SpatialGizmo> &p_gizmo);
diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp
index c547e76e30..d96b003a81 100644
--- a/scene/3d/spatial_velocity_tracker.cpp
+++ b/scene/3d/spatial_velocity_tracker.cpp
@@ -53,11 +53,11 @@ void SpatialVelocityTracker::update_position(const Vector3 &p_position) {
if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest
position_history_len = MIN(position_history.size(), position_history_len + 1);
for (int i = position_history_len - 1; i > 0; i--) {
- position_history[i] = position_history[i - 1];
+ position_history.write[i] = position_history[i - 1];
}
}
- position_history[0] = ph;
+ position_history.write[0] = ph;
}
Vector3 SpatialVelocityTracker::get_tracked_linear_velocity() const {
@@ -114,7 +114,7 @@ void SpatialVelocityTracker::reset(const Vector3 &p_new_pos) {
ph.frame = Engine::get_singleton()->get_idle_frame_ticks();
}
- position_history[0] = ph;
+ position_history.write[0] = ph;
position_history_len = 1;
}
diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp
new file mode 100644
index 0000000000..492c6b806e
--- /dev/null
+++ b/scene/3d/spring_arm.cpp
@@ -0,0 +1,172 @@
+/*************************************************************************/
+/* spring_arm.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 "spring_arm.h"
+#include "engine.h"
+#include "scene/3d/collision_object.h"
+#include "scene/resources/sphere_shape.h"
+#include "servers/physics_server.h"
+
+SpringArm::SpringArm() :
+ spring_length(1),
+ mask(1),
+ current_spring_length(0),
+ margin(0.01) {}
+
+void SpringArm::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ set_process_internal(true);
+ }
+ break;
+ case NOTIFICATION_EXIT_TREE:
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ set_process_internal(false);
+ }
+ break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ process_spring();
+ break;
+ }
+}
+
+void SpringArm::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm::get_hit_length);
+
+ ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm::set_length);
+ ClassDB::bind_method(D_METHOD("get_length"), &SpringArm::get_length);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm::get_shape);
+
+ ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm::add_excluded_object);
+ ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm::remove_excluded_object);
+ ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm::clear_excluded_objects);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm::set_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm::get_mask);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm::get_margin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "spring_length"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin"), "set_margin", "get_margin");
+}
+
+float SpringArm::get_length() const {
+ return spring_length;
+}
+
+void SpringArm::set_length(float p_length) {
+ if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint()))
+ update_gizmo();
+
+ spring_length = p_length;
+}
+
+void SpringArm::set_shape(Ref<Shape> p_shape) {
+ shape = p_shape;
+}
+
+Ref<Shape> SpringArm::get_shape() const {
+ return shape;
+}
+
+void SpringArm::set_mask(uint32_t p_mask) {
+ mask = p_mask;
+}
+
+uint32_t SpringArm::get_mask() {
+ return mask;
+}
+
+float SpringArm::get_margin() {
+ return margin;
+}
+
+void SpringArm::set_margin(float p_margin) {
+ margin = p_margin;
+}
+
+void SpringArm::add_excluded_object(RID p_rid) {
+ excluded_objects.insert(p_rid);
+}
+
+bool SpringArm::remove_excluded_object(RID p_rid) {
+ return excluded_objects.erase(p_rid);
+}
+
+void SpringArm::clear_excluded_objects() {
+ excluded_objects.clear();
+}
+
+float SpringArm::get_hit_length() {
+ return current_spring_length;
+}
+
+void SpringArm::process_spring() {
+ // From
+ real_t motion_delta(1);
+ real_t motion_delta_unsafe(1);
+
+ Vector3 motion;
+ const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
+
+ if (shape.is_null()) {
+ motion = Vector3(cast_direction * (spring_length));
+ PhysicsDirectSpaceState::RayResult r;
+ bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
+ if (intersected) {
+ float dist = get_global_transform().origin.distance_to(r.position);
+ dist -= margin;
+ motion_delta = dist / (spring_length);
+ }
+ } else {
+ motion = Vector3(cast_direction * spring_length);
+ get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
+ }
+
+ current_spring_length = spring_length * motion_delta;
+ Transform childs_transform;
+ childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);
+
+ for (int i = get_child_count() - 1; 0 <= i; --i) {
+
+ Spatial *child = Object::cast_to<Spatial>(get_child(i));
+ if (child) {
+ childs_transform.basis = child->get_global_transform().basis;
+ child->set_global_transform(childs_transform);
+ }
+ }
+}
diff --git a/scene/3d/spring_arm.h b/scene/3d/spring_arm.h
new file mode 100644
index 0000000000..24d912d371
--- /dev/null
+++ b/scene/3d/spring_arm.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* spring_arm.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 SPRING_ARM_H
+#define SPRING_ARM_H
+
+#include "scene/3d/spatial.h"
+
+class SpringArm : public Spatial {
+ GDCLASS(SpringArm, Spatial);
+
+ Ref<Shape> shape;
+ Set<RID> excluded_objects;
+ float spring_length;
+ bool keep_child_basis;
+ float current_spring_length;
+ uint32_t mask;
+ float margin;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_length(float p_length);
+ float get_length() const;
+ void set_shape(Ref<Shape> p_shape);
+ Ref<Shape> get_shape() const;
+ void set_mask(uint32_t p_mask);
+ uint32_t get_mask();
+ void add_excluded_object(RID p_rid);
+ bool remove_excluded_object(RID p_rid);
+ void clear_excluded_objects();
+ float get_hit_length();
+ void set_margin(float p_margin);
+ float get_margin();
+
+ SpringArm();
+
+private:
+ void process_spring();
+};
+
+#endif
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index 385956dc16..f9d096633c 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -366,22 +366,14 @@ void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) {
const Vector3 &right = wheel.m_raycastInfo.m_wheelAxleWS;
Vector3 fwd = up.cross(right);
fwd = fwd.normalized();
- //up = right.cross(fwd);
- //up.normalize();
//rotate around steering over de wheelAxleWS
real_t steering = wheel.steers ? m_steeringValue : 0.0;
- //print_line(itos(p_idx)+": "+rtos(steering));
Basis steeringMat(up, steering);
Basis rotatingMat(right, wheel.m_rotation);
- /*
- if (p_idx==1)
- print_line("steeringMat " +steeringMat);
- */
-
Basis basis2(
right[0], up[0], fwd[0],
right[1], up[1], fwd[1],
@@ -420,8 +412,6 @@ real_t VehicleBody::_ray_cast(int p_idx, PhysicsDirectBodyState *s) {
wheel.m_raycastInfo.m_groundObject = 0;
if (col) {
- //print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target);
- //print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col));
param = source.distance_to(rr.position) / source.distance_to(target);
depth = raylen * param;
wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
@@ -524,7 +514,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, real_t p_rollInfluence) {
+ PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) {
real_t normalLenSqr = normal.length_squared();
//ERR_FAIL_COND( normalLenSqr < real_t(1.1));
@@ -677,8 +667,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
//collapse all those loops into one!
for (int i = 0; i < wheels.size(); i++) {
- m_sideImpulse[i] = real_t(0.);
- m_forwardImpulse[i] = real_t(0.);
+ m_sideImpulse.write[i] = real_t(0.);
+ m_forwardImpulse.write[i] = real_t(0.);
}
{
@@ -693,22 +683,22 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis;
- m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
+ m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
//m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
real_t proj = m_axle[i].dot(surfNormalWS);
- m_axle[i] -= surfNormalWS * proj;
- m_axle[i] = m_axle[i].normalized();
+ m_axle.write[i] -= surfNormalWS * proj;
+ m_axle.write[i] = m_axle[i].normalized();
- m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
- m_forwardWS[i].normalize();
+ m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]);
+ m_forwardWS.write[i].normalize();
_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], wheelInfo.m_rollInfluence);
+ m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence);
- m_sideImpulse[i] *= sideFrictionStiffness2;
+ m_sideImpulse.write[i] *= sideFrictionStiffness2;
}
}
}
@@ -739,7 +729,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
//switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
- m_forwardImpulse[wheel] = real_t(0.);
+ m_forwardImpulse.write[wheel] = real_t(0.);
wheelInfo.m_skidInfo = real_t(1.);
if (wheelInfo.m_raycastInfo.m_isInContact) {
@@ -750,7 +740,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
real_t maximpSquared = maximp * maximpSide;
- m_forwardImpulse[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
+ m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep;
real_t x = (m_forwardImpulse[wheel]) * fwdFactor;
real_t y = (m_sideImpulse[wheel]) * sideFactor;
@@ -772,8 +762,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
for (int wheel = 0; wheel < wheels.size(); wheel++) {
if (m_sideImpulse[wheel] != real_t(0.)) {
if (wheels[wheel]->m_skidInfo < real_t(1.)) {
- m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo;
- m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+ m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
+ m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo;
}
}
}
@@ -942,8 +932,6 @@ VehicleBody::VehicleBody() :
engine_force = 0;
brake = 0;
- friction = 1;
-
state = NULL;
ccd = false;
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
index 1ac3693cc4..68fbf8d873 100644
--- a/scene/3d/vehicle_body.h
+++ b/scene/3d/vehicle_body.h
@@ -168,7 +168,7 @@ class VehicleBody : public RigidBody {
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, real_t p_rollInfluence);
+ void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence);
real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
void _update_friction(PhysicsDirectBodyState *s);
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 00541a7d8a..767518dc83 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -105,12 +105,28 @@ uint32_t VisualInstance::get_layer_mask() const {
return layers;
}
+void VisualInstance::set_layer_mask_bit(int p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_layer_mask(layers | (1 << p_layer));
+ } else {
+ set_layer_mask(layers & (~(1 << p_layer)));
+ }
+}
+
+bool VisualInstance::get_layer_mask_bit(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (layers & (1 << p_layer));
+}
+
void VisualInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid);
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base);
ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance::set_layer_mask);
ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance::get_layer_mask);
+ ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance::get_layer_mask_bit);
ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance::get_transformed_aabb);
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 8458a343b2..9249bc04ce 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -73,6 +73,9 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
+ void set_layer_mask_bit(int p_layer, bool p_enable);
+ bool get_layer_mask_bit(int p_layer) const;
+
VisualInstance();
~VisualInstance();
};
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 670df5cc7f..e846e1763d 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -113,7 +113,7 @@ static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
if (min > rad || max < -rad) return false;
- /*======================== Z-tests ========================*/
+/*======================== Z-tests ========================*/
#define AXISTEST_Z12(a, b, fa, fb) \
p1 = a * v1.x - b * v1.y; \
@@ -409,16 +409,16 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
}
//put this temporarily here, corrected in a later step
- bake_cells[p_idx].albedo[0] += albedo_accum.r;
- bake_cells[p_idx].albedo[1] += albedo_accum.g;
- bake_cells[p_idx].albedo[2] += albedo_accum.b;
- bake_cells[p_idx].emission[0] += emission_accum.r;
- bake_cells[p_idx].emission[1] += emission_accum.g;
- bake_cells[p_idx].emission[2] += emission_accum.b;
- bake_cells[p_idx].normal[0] += normal_accum.x;
- bake_cells[p_idx].normal[1] += normal_accum.y;
- bake_cells[p_idx].normal[2] += normal_accum.z;
- bake_cells[p_idx].alpha += alpha;
+ bake_cells.write[p_idx].albedo[0] += albedo_accum.r;
+ bake_cells.write[p_idx].albedo[1] += albedo_accum.g;
+ bake_cells.write[p_idx].albedo[2] += albedo_accum.b;
+ bake_cells.write[p_idx].emission[0] += emission_accum.r;
+ bake_cells.write[p_idx].emission[1] += emission_accum.g;
+ bake_cells.write[p_idx].emission[2] += emission_accum.b;
+ bake_cells.write[p_idx].normal[0] += normal_accum.x;
+ bake_cells.write[p_idx].normal[1] += normal_accum.y;
+ bake_cells.write[p_idx].normal[2] += normal_accum.z;
+ bake_cells.write[p_idx].alpha += alpha;
} else {
//go down
@@ -465,9 +465,9 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
//sub cell must be created
uint32_t child_idx = bake_cells.size();
- bake_cells[p_idx].children[i] = child_idx;
+ bake_cells.write[p_idx].children[i] = child_idx;
bake_cells.resize(bake_cells.size() + 1);
- bake_cells[child_idx].level = p_level + 1;
+ bake_cells.write[child_idx].level = p_level + 1;
}
_plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb);
@@ -483,7 +483,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color
ret.resize(bake_texture_size * bake_texture_size);
for (int i = 0; i < bake_texture_size * bake_texture_size; i++) {
- ret[i] = p_color_add;
+ ret.write[i] = p_color_add;
}
return ret;
@@ -491,8 +491,6 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color
p_image = p_image->duplicate();
if (p_image->is_compressed()) {
- print_line("DECOMPRESSING!!!!");
-
p_image->decompress();
}
p_image->convert(Image::FORMAT_RGBA8);
@@ -509,7 +507,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color
c.a = r[i * 4 + 3] / 255.0;
- ret[i] = c;
+ ret.write[i] = c;
}
return ret;
@@ -686,13 +684,13 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) {
- bake_light[p_idx].x = p_x;
- bake_light[p_idx].y = p_y;
- bake_light[p_idx].z = p_z;
+ bake_light.write[p_idx].x = p_x;
+ bake_light.write[p_idx].y = p_y;
+ bake_light.write[p_idx].z = p_z;
if (p_level == cell_subdiv - 1) {
- bake_light[p_idx].next_leaf = first_leaf;
+ bake_light.write[p_idx].next_leaf = first_leaf;
first_leaf = p_idx;
} else {
@@ -859,7 +857,6 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
int idx = first_leaf;
while (idx >= 0) {
- //print_line("plot idx " + itos(idx));
Light *light = &light_data[idx];
Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
@@ -949,7 +946,6 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
int idx = first_leaf;
while (idx >= 0) {
- //print_line("plot idx " + itos(idx));
Light *light = &light_data[idx];
Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
@@ -1079,7 +1075,6 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
int idx = first_leaf;
while (idx >= 0) {
- //print_line("plot idx " + itos(idx));
Light *light = &light_data[idx];
Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
@@ -1197,33 +1192,33 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
leaf_voxel_count++;
float alpha = bake_cells[p_idx].alpha;
- bake_cells[p_idx].albedo[0] /= alpha;
- bake_cells[p_idx].albedo[1] /= alpha;
- bake_cells[p_idx].albedo[2] /= alpha;
+ bake_cells.write[p_idx].albedo[0] /= alpha;
+ bake_cells.write[p_idx].albedo[1] /= alpha;
+ bake_cells.write[p_idx].albedo[2] /= alpha;
//transfer emission to light
- bake_cells[p_idx].emission[0] /= alpha;
- bake_cells[p_idx].emission[1] /= alpha;
- bake_cells[p_idx].emission[2] /= alpha;
+ bake_cells.write[p_idx].emission[0] /= alpha;
+ bake_cells.write[p_idx].emission[1] /= alpha;
+ bake_cells.write[p_idx].emission[2] /= alpha;
- bake_cells[p_idx].normal[0] /= alpha;
- bake_cells[p_idx].normal[1] /= alpha;
- bake_cells[p_idx].normal[2] /= alpha;
+ bake_cells.write[p_idx].normal[0] /= alpha;
+ bake_cells.write[p_idx].normal[1] /= alpha;
+ bake_cells.write[p_idx].normal[2] /= alpha;
Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]);
if (n.length() < 0.01) {
//too much fight over normal, zero it
- bake_cells[p_idx].normal[0] = 0;
- bake_cells[p_idx].normal[1] = 0;
- bake_cells[p_idx].normal[2] = 0;
+ bake_cells.write[p_idx].normal[0] = 0;
+ bake_cells.write[p_idx].normal[1] = 0;
+ bake_cells.write[p_idx].normal[2] = 0;
} else {
n.normalize();
- bake_cells[p_idx].normal[0] = n.x;
- bake_cells[p_idx].normal[1] = n.y;
- bake_cells[p_idx].normal[2] = n.z;
+ bake_cells.write[p_idx].normal[0] = n.x;
+ bake_cells.write[p_idx].normal[1] = n.y;
+ bake_cells.write[p_idx].normal[2] = n.z;
}
- bake_cells[p_idx].alpha = 1.0;
+ bake_cells.write[p_idx].alpha = 1.0;
/*if (bake_light.size()) {
for(int i=0;i<6;i++) {
@@ -1235,20 +1230,20 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
//go down
- bake_cells[p_idx].emission[0] = 0;
- bake_cells[p_idx].emission[1] = 0;
- bake_cells[p_idx].emission[2] = 0;
- bake_cells[p_idx].normal[0] = 0;
- bake_cells[p_idx].normal[1] = 0;
- bake_cells[p_idx].normal[2] = 0;
- bake_cells[p_idx].albedo[0] = 0;
- bake_cells[p_idx].albedo[1] = 0;
- bake_cells[p_idx].albedo[2] = 0;
+ bake_cells.write[p_idx].emission[0] = 0;
+ bake_cells.write[p_idx].emission[1] = 0;
+ bake_cells.write[p_idx].emission[2] = 0;
+ bake_cells.write[p_idx].normal[0] = 0;
+ bake_cells.write[p_idx].normal[1] = 0;
+ bake_cells.write[p_idx].normal[2] = 0;
+ bake_cells.write[p_idx].albedo[0] = 0;
+ bake_cells.write[p_idx].albedo[1] = 0;
+ bake_cells.write[p_idx].albedo[2] = 0;
if (bake_light.size()) {
for (int j = 0; j < 6; j++) {
- bake_light[p_idx].accum[j][0] = 0;
- bake_light[p_idx].accum[j][1] = 0;
- bake_light[p_idx].accum[j][2] = 0;
+ bake_light.write[p_idx].accum[j][0] = 0;
+ bake_light.write[p_idx].accum[j][1] = 0;
+ bake_light.write[p_idx].accum[j][2] = 0;
}
}
@@ -1267,29 +1262,29 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
if (bake_light.size() > 0) {
for (int j = 0; j < 6; j++) {
- bake_light[p_idx].accum[j][0] += bake_light[child].accum[j][0];
- bake_light[p_idx].accum[j][1] += bake_light[child].accum[j][1];
- bake_light[p_idx].accum[j][2] += bake_light[child].accum[j][2];
+ bake_light.write[p_idx].accum[j][0] += bake_light[child].accum[j][0];
+ bake_light.write[p_idx].accum[j][1] += bake_light[child].accum[j][1];
+ bake_light.write[p_idx].accum[j][2] += bake_light[child].accum[j][2];
}
- bake_cells[p_idx].emission[0] += bake_cells[child].emission[0];
- bake_cells[p_idx].emission[1] += bake_cells[child].emission[1];
- bake_cells[p_idx].emission[2] += bake_cells[child].emission[2];
+ bake_cells.write[p_idx].emission[0] += bake_cells[child].emission[0];
+ bake_cells.write[p_idx].emission[1] += bake_cells[child].emission[1];
+ bake_cells.write[p_idx].emission[2] += bake_cells[child].emission[2];
}
children_found++;
}
- bake_cells[p_idx].alpha = alpha_average / 8.0;
+ bake_cells.write[p_idx].alpha = alpha_average / 8.0;
if (bake_light.size() && children_found) {
float divisor = Math::lerp(8, children_found, propagation);
for (int j = 0; j < 6; j++) {
- bake_light[p_idx].accum[j][0] /= divisor;
- bake_light[p_idx].accum[j][1] /= divisor;
- bake_light[p_idx].accum[j][2] /= divisor;
+ bake_light.write[p_idx].accum[j][0] /= divisor;
+ bake_light.write[p_idx].accum[j][1] /= divisor;
+ bake_light.write[p_idx].accum[j][2] /= divisor;
}
- bake_cells[p_idx].emission[0] /= divisor;
- bake_cells[p_idx].emission[1] /= divisor;
- bake_cells[p_idx].emission[2] /= divisor;
+ bake_cells.write[p_idx].emission[0] /= divisor;
+ bake_cells.write[p_idx].emission[1] /= divisor;
+ bake_cells.write[p_idx].emission[2] /= divisor;
}
}
}
@@ -1498,12 +1493,8 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
for (int i = 0; i < 6; i++) {
//anisotropic read light
float amount = p_direction.dot(aniso_normal[i]);
- //if (c == 0) {
- // print_line("\t" + itos(n) + " aniso " + itos(i) + " " + rtos(light[cell].accum[i][0]) + " VEC: " + aniso_normal[i]);
- //}
if (amount < 0)
amount = 0;
- //amount = 1;
color[c][n].x += light[cell].accum[i][0] * amount;
color[c][n].y += light[cell].accum[i][1] * amount;
color[c][n].z += light[cell].accum[i][2] * amount;
@@ -1513,8 +1504,6 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
color[c][n].y += cells[cell].emission[1];
color[c][n].z += cells[cell].emission[2];
}
-
- //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]);
}
}
@@ -1559,8 +1548,6 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter);
r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter);
-
- // print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha));
}
Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture) {
@@ -1577,8 +1564,6 @@ Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &
while (dist < max_distance && alpha < 0.95) {
float diameter = MAX(1.0, 2.0 * p_aperture * dist);
- //print_line("VCT: pos " + (p_pos + dist * p_normal) + " dist " + rtos(dist) + " mipmap " + rtos(log2(diameter)) + " alpha " + rtos(alpha));
- //Plane scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
_sample_baked_octree_filtered_and_anisotropic(p_pos + dist * p_normal, p_normal, log2(diameter), scolor, salpha);
float a = (1.0 - alpha);
color += scolor * a;
@@ -1601,7 +1586,6 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3 bitangent = tangent.cross(p_normal).normalized();
Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed();
- // print_line("normal xform: " + normal_xform);
const Vector3 *cone_dirs;
const float *cone_weights;
int cone_dir_count;
@@ -1667,10 +1651,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3 accum;
for (int i = 0; i < cone_dir_count; i++) {
- // if (i > 0)
- // continue;
Vector3 dir = normal_xform.xform(cone_dirs[i]).normalized(); //normal may not completely correct when transformed to cell
- //print_line("direction: " + dir);
accum += _voxel_cone_trace(p_pos, dir, cone_aperture) * cone_weights[i];
}
@@ -1802,7 +1783,6 @@ 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;
@@ -1810,8 +1790,6 @@ void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
case BAKE_MODE_RAY_TRACE: {
pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy;
} break;
- // pixel->light = Vector3(1, 1, 1);
- //}
}
}
@@ -1895,7 +1873,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
if (bake_mode == BAKE_MODE_RAY_TRACE) {
//blur
- print_line("bluring, use pos for separatable copy");
//gauss kernel, 7 step sigma 2
static const float gauss_kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 };
//horizontal pass
@@ -1960,8 +1937,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
#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 schedule(dynamic, 1)
#endif
@@ -2304,7 +2279,6 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
mm->set_transform_format(MultiMesh::TRANSFORM_3D);
mm->set_color_format(MultiMesh::COLOR_8BIT);
- print_line("leaf voxels: " + itos(leaf_voxel_count));
mm->set_instance_count(leaf_voxel_count);
Ref<ArrayMesh> mesh;
@@ -2403,25 +2377,25 @@ PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) {
new_size++;
demap.push_back(i);
}
- remap[i] = c;
+ remap.write[i] = c;
}
Vector<VoxelLightBakerOctree> octree;
octree.resize(new_size);
for (int i = 0; i < new_size; i++) {
- octree[i].alpha = bake_cells[demap[i]].alpha;
+ octree.write[i].alpha = bake_cells[demap[i]].alpha;
for (int j = 0; j < 6; j++) {
for (int k = 0; k < 3; k++) {
float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light
l += bake_cells[demap[i]].emission[k]; //add emission
- octree[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree
+ octree.write[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree
}
}
for (int j = 0; j < 8; j++) {
uint32_t child = bake_cells[demap[i]].children[j];
- octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child];
+ octree.write[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child];
}
}
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index 6993c0a785..76de39c3e6 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -1,5 +1,46 @@
+/*************************************************************************/
+/* animation_blend_space_1d.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 "animation_blend_space_1d.h"
+void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, blend_position));
+}
+Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0;
+}
+
+Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
+ return get_blend_point_node(p_name.operator String().to_int());
+}
+
void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("blend_point_")) {
String left = property.name.get_slicec('/', 0);
@@ -11,6 +52,10 @@ void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const
AnimationRootNode::_validate_property(property);
}
+void AnimationNodeBlendSpace1D::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace1D::add_blend_point, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace1D::set_blend_point_position);
@@ -29,30 +74,37 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace1D::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace1D::get_snap);
- ClassDB::bind_method(D_METHOD("set_blend_pos", "pos"), &AnimationNodeBlendSpace1D::set_blend_pos);
- ClassDB::bind_method(D_METHOD("get_blend_pos"), &AnimationNodeBlendSpace1D::get_blend_pos);
-
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace1D::_tree_changed);
+
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
}
ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "blend_pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_pos", "get_blend_pos");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_value_label", "get_value_label");
}
+void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ for (int i = 0; i < blend_points_used; i++) {
+ ChildNode cn;
+ cn.name = itos(i);
+ cn.node = blend_points[i].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) {
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
+
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
if (p_at_index == -1 || p_at_index == blend_points_used) {
@@ -66,10 +118,10 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_
blend_points[p_at_index].node = p_node;
blend_points[p_at_index].position = p_position;
- blend_points[p_at_index].node->set_parent(this);
- blend_points[p_at_index].node->set_tree(get_tree());
+ blend_points[p_at_index].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
blend_points_used++;
+ emit_signal("tree_changed");
}
void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) {
@@ -83,13 +135,13 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<Anim
ERR_FAIL_COND(p_node.is_null());
if (blend_points[p_point].node.is_valid()) {
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
}
blend_points[p_point].node = p_node;
- blend_points[p_point].node->set_parent(this);
- blend_points[p_point].node->set_tree(get_tree());
+ blend_points[p_point].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+
+ emit_signal("tree_changed");
}
float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const {
@@ -105,14 +157,14 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
for (int i = p_point; i < blend_points_used - 1; i++) {
blend_points[i] = blend_points[i + 1];
}
blend_points_used--;
+ emit_signal("tree_changed");
}
int AnimationNodeBlendSpace1D::get_blend_point_count() const {
@@ -152,14 +204,6 @@ float AnimationNodeBlendSpace1D::get_snap() const {
return snap;
}
-void AnimationNodeBlendSpace1D::set_blend_pos(float p_pos) {
- blend_pos = p_pos;
-}
-
-float AnimationNodeBlendSpace1D::get_blend_pos() const {
- return blend_pos;
-}
-
void AnimationNodeBlendSpace1D::set_value_label(const String &p_label) {
value_label = p_label;
}
@@ -184,9 +228,11 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
if (blend_points_used == 1) {
// only one point available, just play that animation
- return blend_node(blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
+ return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
}
+ float blend_pos = get_parameter(blend_position);
+
float weights[MAX_BLEND_POINTS] = {};
int point_lower = -1;
@@ -253,7 +299,7 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
float max_time_remaining = 0.0;
for (int i = 0; i < blend_points_used; i++) {
- float remaining = blend_node(blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
+ float remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
max_time_remaining = MAX(max_time_remaining, remaining);
}
@@ -267,18 +313,18 @@ String AnimationNodeBlendSpace1D::get_caption() const {
AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() {
+ for (int i = 0; i < MAX_BLEND_POINTS; i++) {
+ blend_points[i].name = itos(i);
+ }
blend_points_used = 0;
max_space = 1;
min_space = -1;
snap = 0.1;
value_label = "value";
+
+ blend_position = "blend_position";
}
AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() {
-
- for (int i = 0; i < blend_points_used; i++) {
- blend_points[i].node->set_parent(this);
- blend_points[i].node->set_tree(get_tree());
- }
}
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index 6e264076c4..a83a813744 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_blend_space_1d.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 ANIMATION_BLEND_SPACE_1D_H
#define ANIMATION_BLEND_SPACE_1D_H
@@ -11,6 +41,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
};
struct BlendPoint {
+ StringName name;
Ref<AnimationRootNode> node;
float position;
};
@@ -18,8 +49,6 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
BlendPoint blend_points[MAX_BLEND_POINTS];
int blend_points_used;
- float blend_pos;
-
float max_space;
float min_space;
@@ -29,11 +58,20 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node);
+ void _tree_changed();
+
+ StringName blend_position;
+
protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
+
void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
void set_blend_point_position(int p_point, float p_position);
void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node);
@@ -52,15 +90,14 @@ public:
void set_snap(float p_snap);
float get_snap() const;
- void set_blend_pos(float p_pos);
- float get_blend_pos() const;
-
void set_value_label(const String &p_label);
String get_value_label() const;
float process(float p_time, bool p_seek);
String get_caption() const;
+ Ref<AnimationNode> get_child_by_name(const StringName &p_name);
+
AnimationNodeBlendSpace1D();
~AnimationNodeBlendSpace1D();
};
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 28e4ca4eda..f3a76b950e 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -1,10 +1,55 @@
+/*************************************************************************/
+/* animation_blend_space_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 "animation_blend_space_2d.h"
#include "math/delaunay.h"
+void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position));
+}
+Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const {
+ return Vector2();
+}
+
+void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ for (int i = 0; i < blend_points_used; i++) {
+ ChildNode cn;
+ cn.name = itos(i);
+ cn.node = blend_points[i].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) {
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
if (p_at_index == -1 || p_at_index == blend_points_used) {
@@ -16,7 +61,7 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_
for (int i = 0; i < triangles.size(); i++) {
for (int j = 0; j < 3; j++) {
if (triangles[i].points[j] >= p_at_index) {
- triangles[i].points[j]++;
+ triangles.write[i].points[j]++;
}
}
}
@@ -24,13 +69,13 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_
blend_points[p_at_index].node = p_node;
blend_points[p_at_index].position = p_position;
- blend_points[p_at_index].node->set_parent(this);
- blend_points[p_at_index].node->set_tree(get_tree());
+ blend_points[p_at_index].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
blend_points_used++;
if (auto_triangles) {
trianges_dirty = true;
}
+ emit_signal("tree_changed");
}
void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) {
@@ -45,12 +90,12 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<Anim
ERR_FAIL_COND(p_node.is_null());
if (blend_points[p_point].node.is_valid()) {
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
}
blend_points[p_point].node = p_node;
- blend_points[p_point].node->set_parent(this);
- blend_points[p_point].node->set_tree(get_tree());
+ blend_points[p_point].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+
+ emit_signal("tree_changed");
}
Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const {
ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2());
@@ -63,8 +108,7 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
for (int i = 0; i < triangles.size(); i++) {
bool erase = false;
@@ -73,7 +117,7 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
erase = true;
break;
} else if (triangles[i].points[j] > p_point) {
- triangles[i].points[j]--;
+ triangles.write[i].points[j]--;
}
}
if (erase) {
@@ -87,6 +131,7 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
blend_points[i] = blend_points[i + 1];
}
blend_points_used--;
+ emit_signal("tree_changed");
}
int AnimationNodeBlendSpace2D::get_blend_point_count() const {
@@ -209,13 +254,6 @@ Vector2 AnimationNodeBlendSpace2D::get_snap() const {
return snap;
}
-void AnimationNodeBlendSpace2D::set_blend_position(const Vector2 &p_pos) {
- blend_pos = p_pos;
-}
-Vector2 AnimationNodeBlendSpace2D::get_blend_position() const {
- return blend_pos;
-}
-
void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) {
x_label = p_label;
}
@@ -256,9 +294,9 @@ Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const {
t.resize(triangles.size() * 3);
for (int i = 0; i < triangles.size(); i++) {
- t[i * 3 + 0] = triangles[i].points[0];
- t[i * 3 + 1] = triangles[i].points[1];
- t[i * 3 + 2] = triangles[i].points[2];
+ t.write[i * 3 + 0] = triangles[i].points[0];
+ t.write[i * 3 + 1] = triangles[i].points[1];
+ t.write[i * 3 + 2] = triangles[i].points[2];
}
return t;
}
@@ -276,7 +314,7 @@ void AnimationNodeBlendSpace2D::_update_triangles() {
Vector<Vector2> points;
points.resize(blend_points_used);
for (int i = 0; i < blend_points_used; i++) {
- points[i] = blend_points[i].position;
+ points.write[i] = blend_points[i].position;
}
Vector<Delaunay2D::Triangle> triangles = Delaunay2D::triangulate(points);
@@ -373,6 +411,8 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
_update_triangles();
+ Vector2 blend_pos = get_parameter(blend_position);
+
if (triangles.size() == 0)
return 0;
@@ -435,7 +475,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
for (int j = 0; j < 3; j++) {
if (i == triangle_points[j]) {
//blend with the given weight
- float t = blend_node(blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
+ float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
if (first || t < mind) {
mind = t;
first = false;
@@ -447,7 +487,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
if (!found) {
//ignore
- blend_node(blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
}
}
return mind;
@@ -479,6 +519,14 @@ bool AnimationNodeBlendSpace2D::get_auto_triangles() const {
return auto_triangles;
}
+Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) {
+ return get_blend_point_node(p_name.operator String().to_int());
+}
+
+void AnimationNodeBlendSpace2D::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
@@ -503,9 +551,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap);
- ClassDB::bind_method(D_METHOD("set_blend_position", "pos"), &AnimationNodeBlendSpace2D::set_blend_position);
- ClassDB::bind_method(D_METHOD("get_blend_position"), &AnimationNodeBlendSpace2D::get_blend_position);
-
ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace2D::set_x_label);
ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace2D::get_x_label);
@@ -520,10 +565,12 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles);
ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles");
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
}
@@ -532,13 +579,15 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "blend_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_position", "get_blend_position");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label");
}
AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
+ for (int i = 0; i < MAX_BLEND_POINTS; i++) {
+ blend_points[i].name = itos(i);
+ }
auto_triangles = true;
blend_points_used = 0;
max_space = Vector2(1, 1);
@@ -547,12 +596,8 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
x_label = "x";
y_label = "y";
trianges_dirty = false;
+ blend_position = "blend_position";
}
AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {
-
- for (int i = 0; i < blend_points_used; i++) {
- blend_points[i].node->set_parent(this);
- blend_points[i].node->set_tree(get_tree());
- }
}
diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h
index 5af0b9ba7f..2c684687de 100644
--- a/scene/animation/animation_blend_space_2d.h
+++ b/scene/animation/animation_blend_space_2d.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_blend_space_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 ANIMATION_BLEND_SPACE_2D_H
#define ANIMATION_BLEND_SPACE_2D_H
@@ -11,6 +41,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
};
struct BlendPoint {
+ StringName name;
Ref<AnimationRootNode> node;
Vector2 position;
};
@@ -24,7 +55,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
Vector<BlendTriangle> triangles;
- Vector2 blend_pos;
+ StringName blend_position;
Vector2 max_space;
Vector2 min_space;
Vector2 snap;
@@ -42,11 +73,18 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
void _update_triangles();
+ void _tree_changed();
+
protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
+
void add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1);
void set_blend_point_position(int p_point, const Vector2 &p_position);
void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node);
@@ -70,9 +108,6 @@ public:
void set_snap(const Vector2 &p_snap);
Vector2 get_snap() const;
- void set_blend_position(const Vector2 &p_pos);
- Vector2 get_blend_position() const;
-
void set_x_label(const String &p_label);
String get_x_label() const;
@@ -87,6 +122,8 @@ public:
void set_auto_triangles(bool p_enable);
bool get_auto_triangles() const;
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
+
AnimationNodeBlendSpace2D();
~AnimationNodeBlendSpace2D();
};
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index feacea5656..b85d4e541e 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1,8 +1,39 @@
+/*************************************************************************/
+/* animation_blend_tree.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 "animation_blend_tree.h"
#include "scene/scene_string_names.h"
void AnimationNodeAnimation::set_animation(const StringName &p_name) {
animation = p_name;
+ _change_notify("animation");
}
StringName AnimationNodeAnimation::get_animation() const {
@@ -13,43 +44,36 @@ float AnimationNodeAnimation::get_playback_time() const {
return time;
}
+Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL;
+
void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
- if (property.name == "animation") {
- AnimationTree *gp = get_tree();
- if (gp && gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
- String anims;
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- if (E != names.front()) {
- anims += ",";
- }
- anims += String(E->get());
- }
- if (anims != String()) {
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = anims;
- }
+ if (property.name == "animation" && get_editable_animation_list) {
+ Vector<String> names = get_editable_animation_list();
+ String anims;
+ for (int i = 0; i < names.size(); i++) {
+
+ if (i > 0) {
+ anims += ",";
}
+ anims += String(names[i]);
+ }
+ if (anims != String()) {
+ property.hint = PROPERTY_HINT_ENUM;
+ property.hint_string = anims;
}
}
-
- AnimationRootNode::_validate_property(property);
}
float AnimationNodeAnimation::process(float p_time, bool p_seek) {
- AnimationPlayer *ap = get_player();
+ AnimationPlayer *ap = state->player;
ERR_FAIL_COND_V(!ap, 0);
- Ref<Animation> anim = ap->get_animation(animation);
- if (!anim.is_valid()) {
+ if (!ap->has_animation(animation)) {
- Ref<AnimationNodeBlendTree> tree = get_parent();
- if (tree.is_valid()) {
+ AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
+ if (tree) {
String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation));
@@ -60,6 +84,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) {
return 0;
}
+ Ref<Animation> anim = ap->get_animation(animation);
+
if (p_seek) {
time = p_time;
step = 0;
@@ -108,6 +134,20 @@ AnimationNodeAnimation::AnimationNodeAnimation() {
////////////////////////////////////////////////////////
+void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::BOOL, active));
+ r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, remaining, PROPERTY_HINT_NONE, "", 0));
+}
+Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
+ if (p_parameter == active || p_parameter == prev_active) {
+ return false;
+ } else {
+ return 0.0;
+ }
+}
+
void AnimationNodeOneShot::set_fadein_time(float p_time) {
fade_in = p_time;
@@ -162,18 +202,6 @@ AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
return mix;
}
-void AnimationNodeOneShot::start() {
- active = true;
- do_start = true;
-}
-void AnimationNodeOneShot::stop() {
- active = false;
-}
-bool AnimationNodeOneShot::is_active() const {
-
- return active;
-}
-
String AnimationNodeOneShot::get_caption() const {
return "OneShot";
}
@@ -184,8 +212,16 @@ bool AnimationNodeOneShot::has_filter() const {
float AnimationNodeOneShot::process(float p_time, bool p_seek) {
+ bool active = get_parameter(this->active);
+ bool prev_active = get_parameter(this->prev_active);
+ float time = get_parameter(this->time);
+ float remaining = get_parameter(this->remaining);
+
if (!active) {
//make it as if this node doesn't exist, pass input 0 by.
+ if (prev_active) {
+ set_parameter(this->prev_active, false);
+ }
return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
}
@@ -193,9 +229,12 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (p_seek)
time = p_time;
+ bool do_start = !prev_active;
+
if (do_start) {
time = 0;
os_seek = true;
+ set_parameter(this->prev_active, true);
}
float blend;
@@ -233,10 +272,15 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (!p_seek) {
time += p_time;
remaining = os_rem;
- if (remaining <= 0)
- active = false;
+ if (remaining <= 0) {
+ set_parameter(this->active, false);
+ set_parameter(this->prev_active, false);
+ }
}
+ set_parameter(this->time, time);
+ set_parameter(this->remaining, remaining);
+
return MAX(main_rem, remaining);
}
void AnimationNodeOneShot::set_use_sync(bool p_sync) {
@@ -269,10 +313,6 @@ void AnimationNodeOneShot::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
- ClassDB::bind_method(D_METHOD("start"), &AnimationNodeOneShot::start);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeOneShot::stop);
- ClassDB::bind_method(D_METHOD("is_active"), &AnimationNodeOneShot::is_active);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
@@ -288,8 +328,8 @@ void AnimationNodeOneShot::_bind_methods() {
ADD_GROUP("", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
- BIND_CONSTANT(MIX_MODE_BLEND)
- BIND_CONSTANT(MIX_MODE_ADD)
+ BIND_ENUM_CONSTANT(MIX_MODE_BLEND)
+ BIND_ENUM_CONSTANT(MIX_MODE_ADD)
}
AnimationNodeOneShot::AnimationNodeOneShot() {
@@ -297,89 +337,142 @@ AnimationNodeOneShot::AnimationNodeOneShot() {
add_input("in");
add_input("shot");
- time = 0;
fade_in = 0.1;
fade_out = 0.1;
autorestart = false;
autorestart_delay = 1;
- autorestart_remaining = 0;
+
mix = MIX_MODE_BLEND;
- active = false;
- do_start = false;
sync = false;
+
+ active = "active";
+ prev_active = "prev_active";
+ time = "time";
+ remaining = "remaining";
}
////////////////////////////////////////////////
-void AnimationNodeAdd::set_amount(float p_amount) {
- amount = p_amount;
+void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
}
-
-float AnimationNodeAdd::get_amount() const {
- return amount;
+Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0;
}
-String AnimationNodeAdd::get_caption() const {
- return "Add";
+String AnimationNodeAdd2::get_caption() const {
+ return "Add2";
}
-void AnimationNodeAdd::set_use_sync(bool p_sync) {
+void AnimationNodeAdd2::set_use_sync(bool p_sync) {
sync = p_sync;
}
-bool AnimationNodeAdd::is_using_sync() const {
+bool AnimationNodeAdd2::is_using_sync() const {
return sync;
}
-bool AnimationNodeAdd::has_filter() const {
+bool AnimationNodeAdd2::has_filter() const {
return true;
}
-float AnimationNodeAdd::process(float p_time, bool p_seek) {
+float AnimationNodeAdd2::process(float p_time, bool p_seek) {
+ float amount = get_parameter(add_amount);
float rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
return rem0;
}
-void AnimationNodeAdd::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd::get_amount);
+void AnimationNodeAdd2::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd::set_use_sync);
- ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd::is_using_sync);
+ ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
+ ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
-AnimationNodeAdd::AnimationNodeAdd() {
+AnimationNodeAdd2::AnimationNodeAdd2() {
+ add_amount = "add_amount";
add_input("in");
add_input("add");
- amount = 0;
sync = false;
}
-/////////////////////////////////////////////
+////////////////////////////////////////////////
+
+void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
+}
+Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0;
+}
+
+String AnimationNodeAdd3::get_caption() const {
+ return "Add3";
+}
+void AnimationNodeAdd3::set_use_sync(bool p_sync) {
+
+ sync = p_sync;
+}
+
+bool AnimationNodeAdd3::is_using_sync() const {
+
+ return sync;
+}
+
+bool AnimationNodeAdd3::has_filter() const {
+
+ return true;
+}
+
+float AnimationNodeAdd3::process(float p_time, bool p_seek) {
+
+ float amount = get_parameter(add_amount);
+ blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_PASS, !sync);
+ float rem0 = blend_input(1, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
+ blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_PASS, !sync);
+
+ return rem0;
+}
+
+void AnimationNodeAdd3::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
+ ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
+}
-void AnimationNodeBlend2::set_amount(float p_amount) {
- amount = p_amount;
+AnimationNodeAdd3::AnimationNodeAdd3() {
+
+ add_amount = "add_amount";
+ add_input("-add");
+ add_input("in");
+ add_input("+add");
+ sync = false;
}
+/////////////////////////////////////////////
-float AnimationNodeBlend2::get_amount() const {
- return amount;
+void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
+}
+Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0; //for blend amount
}
+
String AnimationNodeBlend2::get_caption() const {
return "Blend2";
}
float AnimationNodeBlend2::process(float p_time, bool p_seek) {
+ float amount = get_parameter(blend_amount);
+
float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync);
float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
@@ -402,31 +495,25 @@ bool AnimationNodeBlend2::has_filter() const {
}
void AnimationNodeBlend2::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend2::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend2::get_amount);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend2::AnimationNodeBlend2() {
+ blend_amount = "blend_amount";
add_input("in");
add_input("blend");
sync = false;
-
- amount = 0;
}
//////////////////////////////////////
-void AnimationNodeBlend3::set_amount(float p_amount) {
- amount = p_amount;
+void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
}
-
-float AnimationNodeBlend3::get_amount() const {
- return amount;
+Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0; //for blend amount
}
String AnimationNodeBlend3::get_caption() const {
@@ -445,6 +532,7 @@ bool AnimationNodeBlend3::is_using_sync() const {
float AnimationNodeBlend3::process(float p_time, bool p_seek) {
+ float amount = get_parameter(blend_amount);
float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync);
float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync);
float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync);
@@ -454,31 +542,26 @@ float AnimationNodeBlend3::process(float p_time, bool p_seek) {
void AnimationNodeBlend3::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend3::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend3::get_amount);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend3::AnimationNodeBlend3() {
+ blend_amount = "blend_amount";
add_input("-blend");
add_input("in");
add_input("+blend");
sync = false;
- amount = 0;
}
/////////////////////////////////
-void AnimationNodeTimeScale::set_scale(float p_scale) {
- scale = p_scale;
+void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, scale, PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"));
}
-
-float AnimationNodeTimeScale::get_scale() const {
- return scale;
+Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
+ return 1.0; //initial timescale
}
String AnimationNodeTimeScale::get_caption() const {
@@ -487,6 +570,7 @@ String AnimationNodeTimeScale::get_caption() const {
float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
+ float scale = get_parameter(this->scale);
if (p_seek) {
return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
} else {
@@ -495,25 +579,19 @@ float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
}
void AnimationNodeTimeScale::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_scale", "scale"), &AnimationNodeTimeScale::set_scale);
- ClassDB::bind_method(D_METHOD("get_scale"), &AnimationNodeTimeScale::get_scale);
-
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"), "set_scale", "get_scale");
}
AnimationNodeTimeScale::AnimationNodeTimeScale() {
+ scale = "scale";
add_input("in");
- scale = 1.0;
}
////////////////////////////////////
-void AnimationNodeTimeSeek::set_seek_pos(float p_seek_pos) {
- seek_pos = p_seek_pos;
+void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
}
-
-float AnimationNodeTimeSeek::get_seek_pos() const {
- return seek_pos;
+Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
+ return 1.0; //initial timescale
}
String AnimationNodeTimeSeek::get_caption() const {
@@ -522,11 +600,12 @@ String AnimationNodeTimeSeek::get_caption() const {
float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
+ float seek_pos = get_parameter(this->seek_pos);
if (p_seek) {
return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
} else if (seek_pos >= 0) {
float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false);
- seek_pos = -1;
+ set_parameter(this->seek_pos, -1.0); //reset
_change_notify("seek_pos");
return ret;
} else {
@@ -535,19 +614,41 @@ float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
}
void AnimationNodeTimeSeek::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_seek_pos", "seek_pos"), &AnimationNodeTimeSeek::set_seek_pos);
- ClassDB::bind_method(D_METHOD("get_seek_pos"), &AnimationNodeTimeSeek::get_seek_pos);
-
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "seek_pos", PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"), "set_seek_pos", "get_seek_pos");
}
+
AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
add_input("in");
- seek_pos = -1;
+ seek_pos = "seek_position";
}
/////////////////////////////////////////////////
+void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
+
+ String anims;
+ for (int i = 0; i < enabled_inputs; i++) {
+ if (i > 0) {
+ anims += ",";
+ }
+ anims += inputs[i].name;
+ }
+
+ r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
+ r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, prev_xfading, PROPERTY_HINT_NONE, "", 0));
+}
+Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
+ if (p_parameter == time || p_parameter == prev_xfading) {
+ return 0.0;
+ } else if (p_parameter == prev || p_parameter == prev_current) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
String AnimationNodeTransition::get_caption() const {
return "Transition";
}
@@ -593,18 +694,12 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
-void AnimationNodeTransition::set_current(int p_current) {
-
- if (current == p_current)
- return;
- ERR_FAIL_INDEX(p_current, enabled_inputs);
-
+#if 0
Ref<AnimationNodeBlendTree> tree = get_parent();
if (tree.is_valid() && current >= 0) {
prev = current;
- prev_xfading = xfade;
- prev_time = time;
+ prev_xfading = xfade;
time = 0;
current = p_current;
switched = true;
@@ -612,11 +707,8 @@ void AnimationNodeTransition::set_current(int p_current) {
} else {
current = p_current;
}
-}
+#endif
-int AnimationNodeTransition::get_current() const {
- return current;
-}
void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
xfade = p_fade;
}
@@ -627,9 +719,34 @@ float AnimationNodeTransition::get_cross_fade_time() const {
float AnimationNodeTransition::process(float p_time, bool p_seek) {
+ int current = get_parameter(this->current);
+ int prev = get_parameter(this->prev);
+ int prev_current = get_parameter(this->prev_current);
+
+ float time = get_parameter(this->time);
+ float prev_xfading = get_parameter(this->prev_xfading);
+
+ bool switched = current != prev_current;
+
+ if (switched) {
+ set_parameter(this->prev_current, current);
+ set_parameter(this->prev, prev_current);
+
+ prev = prev_current;
+ prev_xfading = xfade;
+ time = 0;
+ switched = true;
+ }
+
+ if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) {
+ return 0;
+ }
+
+ float rem = 0;
+
if (prev < 0) { // process current animation, check for transition
- float rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
+ rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
if (p_seek)
time = p_time;
@@ -638,16 +755,13 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
if (inputs[current].auto_advance && rem <= xfade) {
- set_current((current + 1) % enabled_inputs);
+ set_parameter(this->current, (current + 1) % enabled_inputs);
}
- return rem;
} else { // cross-fading from prev to current
float blend = xfade ? (prev_xfading / xfade) : 1;
- float rem;
-
if (!p_seek && switched) { //just switched, seek to start of current
rem = blend_input(current, 0, true, 1.0 - blend, FILTER_IGNORE, false);
@@ -666,28 +780,19 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
time += p_time;
prev_xfading -= p_time;
if (prev_xfading < 0) {
- prev = -1;
+ set_parameter(this->prev, -1);
}
}
-
- return rem;
}
+
+ set_parameter(this->time, time);
+ set_parameter(this->prev_xfading, prev_xfading);
+
+ return rem;
}
void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
- if (property.name == "current" && enabled_inputs > 0) {
- property.hint = PROPERTY_HINT_ENUM;
- String anims;
- for (int i = 0; i < enabled_inputs; i++) {
- if (i > 0) {
- anims += ",";
- }
- anims += inputs[i].name;
- }
- property.hint_string = anims;
- }
-
if (property.name.begins_with("input_")) {
String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
if (n != "count") {
@@ -712,14 +817,10 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
- ClassDB::bind_method(D_METHOD("set_current", "index"), &AnimationNodeTransition::set_current);
- ClassDB::bind_method(D_METHOD("get_current"), &AnimationNodeTransition::get_current);
-
ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "current", PROPERTY_HINT_RANGE, "0,64,1"), "set_current", "get_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time");
for (int i = 0; i < MAX_INPUTS; i++) {
@@ -729,13 +830,15 @@ void AnimationNodeTransition::_bind_methods() {
}
AnimationNodeTransition::AnimationNodeTransition() {
+
+ prev_xfading = "prev_xfading";
+ prev = "prev";
+ time = "time";
+ current = "current";
+ prev_current = "prev_current";
+ ;
+
enabled_inputs = 0;
- xfade = 0;
- current = -1;
- prev = -1;
- prev_time = 0;
- prev_xfading = 0;
- switched = false;
for (int i = 0; i < MAX_INPUTS; i++) {
inputs[i].auto_advance = false;
inputs[i].name = itos(i + 1);
@@ -757,69 +860,102 @@ AnimationNodeOutput::AnimationNodeOutput() {
}
///////////////////////////////////////////////////////
-void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node) {
+void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
ERR_FAIL_COND(nodes.has(p_name));
ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
- ERR_FAIL_COND(p_node->get_tree() != NULL);
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(String(p_name).find("/") != -1);
- nodes[p_name] = p_node;
- p_node->set_parent(this);
- p_node->set_tree(get_tree());
+ Node n;
+ n.node = p_node;
+ n.position = p_position;
+ n.connections.resize(n.node->get_input_count());
+ nodes[p_name] = n;
emit_changed();
+ emit_signal("tree_changed");
+
+ p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+ p_node->connect("changed", this, "_node_changed", varray(p_name), CONNECT_REFERENCE_COUNTED);
}
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
- return nodes[p_name];
+ return nodes[p_name].node;
}
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- if (E->get() == p_node) {
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ if (E->get().node == p_node) {
return E->key();
}
}
ERR_FAIL_V(StringName());
}
+
+void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) {
+ ERR_FAIL_COND(!nodes.has(p_node));
+ nodes[p_node].position = p_position;
+}
+
+Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const {
+ ERR_FAIL_COND_V(!nodes.has(p_node), Vector2());
+ return nodes[p_node].position;
+}
+
+void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ Vector<StringName> ns;
+
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ ns.push_back(E->key());
+ }
+
+ ns.sort_custom<StringName::AlphCompare>();
+
+ for (int i = 0; i < ns.size(); i++) {
+ ChildNode cn;
+ cn.name = ns[i];
+ cn.node = nodes[cn.name].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
return nodes.has(p_name);
}
+Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>());
+ return nodes[p_name].connections;
+}
void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
ERR_FAIL_COND(!nodes.has(p_name));
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
{
- //erase node connections
- Ref<AnimationNode> node = nodes[p_name];
- for (int i = 0; i < node->get_input_count(); i++) {
- node->set_input_connection(i, StringName());
- }
- node->set_parent(NULL);
- node->set_tree(NULL);
+ Ref<AnimationNode> node = nodes[p_name].node;
+ node->disconnect("tree_changed", this, "_tree_changed");
+ node->disconnect("changed", this, "_node_changed");
}
nodes.erase(p_name);
//erase connections to name
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- if (node->get_input_connection(i) == p_name) {
- node->set_input_connection(i, StringName());
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ if (E->get().connections[i] == p_name) {
+ E->get().connections.write[i] = StringName();
}
}
}
emit_changed();
+ emit_signal("tree_changed");
}
void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) {
@@ -829,18 +965,24 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output);
+ nodes[p_name].node->disconnect("changed", this, "_node_changed");
+
nodes[p_new_name] = nodes[p_name];
nodes.erase(p_name);
//rename connections
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- if (node->get_input_connection(i) == p_name) {
- node->set_input_connection(i, p_new_name);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ if (E->get().connections[i] == p_name) {
+ E->get().connections.write[i] = p_new_name;
}
}
}
+ //connection must be done with new name
+ nodes[p_new_name].node->connect("changed", this, "_node_changed", varray(p_new_name), CONNECT_REFERENCE_COUNTED);
+
+ emit_signal("tree_changed");
}
void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) {
@@ -850,18 +992,18 @@ void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_
ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_input_node == p_output_node);
- Ref<AnimationNode> input = nodes[p_input_node];
- ERR_FAIL_INDEX(p_input_index, input->get_input_count());
+ Ref<AnimationNode> input = nodes[p_input_node].node;
+ ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- StringName output = node->get_input_connection(i);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ StringName output = E->get().connections[i];
ERR_FAIL_COND(output == p_output_node);
}
}
- input->set_input_connection(p_input_index, p_output_node);
+ nodes[p_input_node].connections.write[p_input_index] = p_output_node;
+
emit_changed();
}
@@ -869,20 +1011,10 @@ void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_inp
ERR_FAIL_COND(!nodes.has(p_node));
- Ref<AnimationNode> input = nodes[p_node];
- ERR_FAIL_INDEX(p_input_index, input->get_input_count());
+ Ref<AnimationNode> input = nodes[p_node].node;
+ ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
- input->set_input_connection(p_input_index, StringName());
-}
-
-float AnimationNodeBlendTree::get_connection_activity(const StringName &p_input_node, int p_input_index) const {
-
- ERR_FAIL_COND_V(!nodes.has(p_input_node), 0);
-
- Ref<AnimationNode> input = nodes[p_input_node];
- ERR_FAIL_INDEX_V(p_input_index, input->get_input_count(), 0);
-
- return input->get_input_activity(p_input_index);
+ nodes[p_node].connections.write[p_input_index] = StringName();
}
AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const {
@@ -899,20 +1031,19 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
return CONNECTION_ERROR_SAME_NODE;
}
- Ref<AnimationNode> input = nodes[p_input_node];
+ Ref<AnimationNode> input = nodes[p_input_node].node;
- if (p_input_index < 0 || p_input_index >= input->get_input_count()) {
+ if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
return CONNECTION_ERROR_NO_INPUT_INDEX;
}
- if (input->get_input_connection(p_input_index) != StringName()) {
+ if (nodes[p_input_node].connections[p_input_index] != StringName()) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- StringName output = node->get_input_connection(i);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ StringName output = E->get().connections[i];
if (output == p_output_node) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
@@ -923,10 +1054,9 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- StringName output = node->get_input_connection(i);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ StringName output = E->get().connections[i];
if (output != StringName()) {
NodeConnection nc;
nc.input_node = E->key();
@@ -944,13 +1074,13 @@ String AnimationNodeBlendTree::get_caption() const {
float AnimationNodeBlendTree::process(float p_time, bool p_seek) {
- Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output];
- return blend_node(output, p_time, p_seek, 1.0);
+ Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
+ return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, 1.0);
}
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
r_list->push_back(E->key());
}
}
@@ -965,20 +1095,15 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const {
return graph_offset;
}
-void AnimationNodeBlendTree::set_tree(AnimationTree *p_player) {
-
- AnimationNode::set_tree(p_player);
-
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- node->set_tree(p_player);
- }
+Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
+ return get_node(p_name);
}
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
if (name.begins_with("nodes/")) {
+
String node_name = name.get_slicec('/', 1);
String what = name.get_slicec('/', 2);
@@ -993,7 +1118,7 @@ bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_val
if (what == "position") {
if (nodes.has(node_name)) {
- nodes[node_name]->set_position(p_value);
+ nodes[node_name].position = p_value;
}
return true;
}
@@ -1020,7 +1145,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
if (what == "node") {
if (nodes.has(node_name)) {
- r_ret = nodes[node_name];
+ r_ret = nodes[node_name].node;
return true;
}
}
@@ -1028,7 +1153,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
if (what == "position") {
if (nodes.has(node_name)) {
- r_ret = nodes[node_name]->get_position();
+ r_ret = nodes[node_name].position;
return true;
}
}
@@ -1055,7 +1180,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
names.push_back(E->key());
}
names.sort_custom<StringName::AlphCompare>();
@@ -1063,7 +1188,7 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
String name = E->get();
if (name != "output") {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
@@ -1071,9 +1196,19 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeBlendTree::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
+void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
+
+ ERR_FAIL_COND(!nodes.has(p_node));
+ nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
+}
+
void AnimationNodeBlendTree::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeBlendTree::add_node);
+ ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node);
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node);
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node);
@@ -1081,9 +1216,15 @@ void AnimationNodeBlendTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node);
ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node);
+ ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position);
+ ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position);
+
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendTree::_tree_changed);
+ ClassDB::bind_method(D_METHOD("_node_changed", "node"), &AnimationNodeBlendTree::_node_changed);
+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset");
BIND_CONSTANT(CONNECTION_OK);
@@ -1098,15 +1239,12 @@ AnimationNodeBlendTree::AnimationNodeBlendTree() {
Ref<AnimationNodeOutput> output;
output.instance();
- output->set_position(Vector2(300, 150));
- output->set_parent(this);
- nodes["output"] = output;
+ Node n;
+ n.node = output;
+ n.position = Vector2(300, 150);
+ n.connections.resize(1);
+ nodes["output"] = n;
}
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
-
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- E->get()->set_parent(NULL);
- E->get()->set_tree(NULL);
- }
}
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 8d7932196c..4ca11e464b 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_blend_tree.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 ANIMATION_BLEND_TREE_H
#define ANIMATION_BLEND_TREE_H
@@ -20,6 +50,8 @@ protected:
static void _bind_methods();
public:
+ static Vector<String> (*get_editable_animation_list)();
+
virtual String get_caption() const;
virtual float process(float p_time, bool p_seek);
@@ -41,8 +73,6 @@ public:
};
private:
- bool active;
- bool do_start;
float fade_in;
float fade_out;
@@ -51,15 +81,25 @@ private:
float autorestart_random_delay;
MixMode mix;
- float time;
- float remaining;
- float autorestart_remaining;
bool sync;
+ /* bool active;
+ bool do_start;
+ float time;
+ float remaining;*/
+
+ StringName active;
+ StringName prev_active;
+ StringName time;
+ StringName remaining;
+
protected:
static void _bind_methods();
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
void set_fadein_time(float p_time);
@@ -79,10 +119,6 @@ public:
void set_mix_mode(MixMode p_mix);
MixMode get_mix_mode() const;
- void start();
- void stop();
- bool is_active() const;
-
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -94,20 +130,44 @@ public:
VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
-class AnimationNodeAdd : public AnimationNode {
- GDCLASS(AnimationNodeAdd, AnimationNode);
+class AnimationNodeAdd2 : public AnimationNode {
+ GDCLASS(AnimationNodeAdd2, AnimationNode);
- float amount;
+ StringName add_amount;
bool sync;
protected:
static void _bind_methods();
public:
+ void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
- void set_amount(float p_amount);
- float get_amount() const;
+ void set_use_sync(bool p_sync);
+ bool is_using_sync() const;
+
+ virtual bool has_filter() const;
+ virtual float process(float p_time, bool p_seek);
+
+ AnimationNodeAdd2();
+};
+
+class AnimationNodeAdd3 : public AnimationNode {
+ GDCLASS(AnimationNodeAdd3, AnimationNode);
+
+ StringName add_amount;
+ bool sync;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -115,25 +175,25 @@ public:
virtual bool has_filter() const;
virtual float process(float p_time, bool p_seek);
- AnimationNodeAdd();
+ AnimationNodeAdd3();
};
class AnimationNodeBlend2 : public AnimationNode {
GDCLASS(AnimationNodeBlend2, AnimationNode);
- float amount;
+ StringName blend_amount;
bool sync;
protected:
static void _bind_methods();
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
virtual float process(float p_time, bool p_seek);
- void set_amount(float p_amount);
- float get_amount() const;
-
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -144,17 +204,17 @@ public:
class AnimationNodeBlend3 : public AnimationNode {
GDCLASS(AnimationNodeBlend3, AnimationNode);
- float amount;
+ StringName blend_amount;
bool sync;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_amount(float p_amount);
- float get_amount() const;
+ virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -166,16 +226,16 @@ public:
class AnimationNodeTimeScale : public AnimationNode {
GDCLASS(AnimationNodeTimeScale, AnimationNode);
- float scale;
+ StringName scale;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_scale(float p_scale);
- float get_scale() const;
+ virtual String get_caption() const;
float process(float p_time, bool p_seek);
@@ -185,16 +245,16 @@ public:
class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
- float seek_pos;
+ StringName seek_pos;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_seek_pos(float p_sec);
- float get_seek_pos() const;
+ virtual String get_caption() const;
float process(float p_time, bool p_seek);
@@ -217,13 +277,18 @@ class AnimationNodeTransition : public AnimationNode {
InputData inputs[MAX_INPUTS];
int enabled_inputs;
- float prev_time;
+ /*
float prev_xfading;
int prev;
- bool switched;
-
float time;
int current;
+ int prev_current; */
+
+ StringName prev_xfading;
+ StringName prev;
+ StringName time;
+ StringName current;
+ StringName prev_current;
float xfade;
@@ -234,6 +299,9 @@ protected:
void _validate_property(PropertyInfo &property) const;
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
void set_enabled_inputs(int p_inputs);
@@ -245,9 +313,6 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
- void set_current(int p_current);
- int get_current() const;
-
void set_cross_fade_time(float p_fade);
float get_cross_fade_time() const;
@@ -269,10 +334,19 @@ public:
class AnimationNodeBlendTree : public AnimationRootNode {
GDCLASS(AnimationNodeBlendTree, AnimationRootNode)
- Map<StringName, Ref<AnimationNode> > nodes;
+ struct Node {
+ Ref<AnimationNode> node;
+ Vector2 position;
+ Vector<StringName> connections;
+ };
+
+ Map<StringName, Node> nodes;
Vector2 graph_offset;
+ void _tree_changed();
+ void _node_changed(const StringName &p_node);
+
protected:
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_value);
@@ -290,16 +364,21 @@ public:
//no need to check for cycles due to tree topology
};
- void add_node(const StringName &p_name, Ref<AnimationNode> p_node);
+ void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
bool has_node(const StringName &p_name) const;
StringName get_node_name(const Ref<AnimationNode> &p_node) const;
+ Vector<StringName> get_node_connection_array(const StringName &p_name) const;
+
+ void set_node_position(const StringName &p_node, const Vector2 &p_position);
+ Vector2 get_node_position(const StringName &p_node) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node);
void disconnect_node(const StringName &p_node, int p_input_index);
- float get_connection_activity(const StringName &p_input_node, int p_input_index) const;
struct NodeConnection {
StringName input_node;
@@ -318,7 +397,8 @@ public:
void set_graph_offset(const Vector2 &p_graph_offset);
Vector2 get_graph_offset() const;
- virtual void set_tree(AnimationTree *p_player);
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
+
AnimationNodeBlendTree();
~AnimationNodeBlendTree();
};
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
index 949a0be3bc..756907c41c 100644
--- a/scene/animation/animation_cache.cpp
+++ b/scene/animation/animation_cache.cpp
@@ -43,7 +43,7 @@ void AnimationCache::_node_exit_tree(Node *p_node) {
if (path_cache[i].node != p_node)
continue;
- path_cache[i].valid = false; //invalidate path cache
+ path_cache.write[i].valid = false; //invalidate path cache
}
}
@@ -196,7 +196,7 @@ void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform
ERR_FAIL_COND(!cache_valid);
ERR_FAIL_INDEX(p_idx, path_cache.size());
- Path &p = path_cache[p_idx];
+ Path &p = path_cache.write[p_idx];
if (!p.valid)
return;
@@ -217,7 +217,7 @@ void AnimationCache::set_track_value(int p_idx, const Variant &p_value) {
ERR_FAIL_COND(!cache_valid);
ERR_FAIL_INDEX(p_idx, path_cache.size());
- Path &p = path_cache[p_idx];
+ Path &p = path_cache.write[p_idx];
if (!p.valid)
return;
@@ -232,7 +232,7 @@ void AnimationCache::call_track(int p_idx, const StringName &p_method, const Var
ERR_FAIL_COND(!cache_valid);
ERR_FAIL_INDEX(p_idx, path_cache.size());
- Path &p = path_cache[p_idx];
+ Path &p = path_cache.write[p_idx];
if (!p.valid)
return;
@@ -297,11 +297,11 @@ void AnimationCache::set_all(float p_time, float p_delta) {
call_track(i, name, NULL, 0, err);
} else {
- Vector<Variant *> argptrs;
+ Vector<const Variant *> argptrs;
argptrs.resize(args.size());
for (int j = 0; j < args.size(); j++) {
- argptrs[j] = &args[j];
+ argptrs.write[j] = &args.write[j];
}
call_track(i, name, (const Variant **)&argptrs[0], args.size(), err);
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index c5ad980806..837723450c 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_node_state_machine.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 "animation_node_state_machine.h"
/////////////////////////////////////////////////
@@ -20,6 +50,26 @@ bool AnimationNodeStateMachineTransition::has_auto_advance() const {
return auto_advance;
}
+void AnimationNodeStateMachineTransition::set_advance_condition(const StringName &p_condition) {
+ String cs = p_condition;
+ ERR_FAIL_COND(cs.find("/") != -1 || cs.find(":") != -1);
+ advance_condition = p_condition;
+ if (cs != String()) {
+ advance_condition_name = "conditions/" + cs;
+ } else {
+ advance_condition_name = StringName();
+ }
+ emit_signal("advance_condition_changed");
+}
+
+StringName AnimationNodeStateMachineTransition::get_advance_condition() const {
+ return advance_condition;
+}
+
+StringName AnimationNodeStateMachineTransition::get_advance_condition_name() const {
+ return advance_condition_name;
+}
+
void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) {
ERR_FAIL_COND(p_xfade < 0);
@@ -56,6 +106,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_advance", "auto_advance"), &AnimationNodeStateMachineTransition::set_auto_advance);
ClassDB::bind_method(D_METHOD("has_auto_advance"), &AnimationNodeStateMachineTransition::has_auto_advance);
+ ClassDB::bind_method(D_METHOD("set_advance_condition", "name"), &AnimationNodeStateMachineTransition::set_advance_condition);
+ ClassDB::bind_method(D_METHOD("get_advance_condition"), &AnimationNodeStateMachineTransition::get_advance_condition);
+
ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time);
@@ -67,13 +120,16 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,AtEnd"), "set_switch_mode", "get_switch_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "advance_condition"), "set_advance_condition", "get_advance_condition");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
- BIND_CONSTANT(SWITCH_MODE_IMMEDIATE);
- BIND_CONSTANT(SWITCH_MODE_SYNC);
- BIND_CONSTANT(SWITCH_MODE_AT_END);
+ BIND_ENUM_CONSTANT(SWITCH_MODE_IMMEDIATE);
+ BIND_ENUM_CONSTANT(SWITCH_MODE_SYNC);
+ BIND_ENUM_CONSTANT(SWITCH_MODE_AT_END);
+
+ ADD_SIGNAL(MethodInfo("advance_condition_changed"));
}
AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
@@ -85,277 +141,240 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
priority = 1;
}
-///////////////////////////////////////////////////////
-void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node) {
-
- ERR_FAIL_COND(states.has(p_name));
- ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
- ERR_FAIL_COND(p_node->get_tree() != NULL);
- ERR_FAIL_COND(String(p_name).find("/") != -1);
- states[p_name] = p_node;
+////////////////////////////////////////////////////////
- p_node->set_parent(this);
- p_node->set_tree(get_tree());
+void AnimationNodeStateMachinePlayback::travel(const StringName &p_state) {
- emit_changed();
+ start_request_travel = true;
+ start_request = p_state;
+ stop_request = false;
}
-Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const {
-
- ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>());
-
- return states[p_name];
+void AnimationNodeStateMachinePlayback::start(const StringName &p_state) {
+ start_request_travel = false;
+ start_request = p_state;
+ stop_request = false;
}
+void AnimationNodeStateMachinePlayback::stop() {
-StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const {
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
- if (E->get() == p_node) {
- return E->key();
- }
- }
-
- ERR_FAIL_V(StringName());
+ stop_request = true;
}
-
-bool AnimationNodeStateMachine::has_node(const StringName &p_name) const {
- return states.has(p_name);
+bool AnimationNodeStateMachinePlayback::is_playing() const {
+ return playing;
+}
+StringName AnimationNodeStateMachinePlayback::get_current_node() const {
+ return current;
+}
+StringName AnimationNodeStateMachinePlayback::get_blend_from_node() const {
+ return fading_from;
+}
+Vector<StringName> AnimationNodeStateMachinePlayback::get_travel_path() const {
+ return path;
+}
+float AnimationNodeStateMachinePlayback::get_current_play_pos() const {
+ return pos_current;
+}
+float AnimationNodeStateMachinePlayback::get_current_length() const {
+ return len_current;
}
-void AnimationNodeStateMachine::remove_node(const StringName &p_name) {
-
- ERR_FAIL_COND(!states.has(p_name));
-
- {
- //erase node connections
- Ref<AnimationNode> node = states[p_name];
- for (int i = 0; i < node->get_input_count(); i++) {
- node->set_input_connection(i, StringName());
- }
- node->set_parent(NULL);
- node->set_tree(NULL);
- }
- states.erase(p_name);
- path.erase(p_name);
+bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *sm, const StringName &p_travel) {
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_name || transitions[i].to == p_name) {
- transitions.remove(i);
- i--;
- }
- }
+ ERR_FAIL_COND_V(!playing, false);
+ ERR_FAIL_COND_V(!sm->states.has(p_travel), false);
+ ERR_FAIL_COND_V(!sm->states.has(current), false);
- if (start_node == p_name) {
- start_node = StringName();
- }
+ path.clear(); //a new one will be needed
- if (end_node == p_name) {
- end_node = StringName();
- }
+ if (current == p_travel)
+ return true; //nothing to do
- if (playing && current == p_name) {
- stop();
- }
- emit_changed();
-}
+ loops_current = 0; // reset loops, so fade does not happen immediately
-void AnimationNodeStateMachine::rename_node(const StringName &p_name, const StringName &p_new_name) {
+ Vector2 current_pos = sm->states[current].position;
+ Vector2 target_pos = sm->states[p_travel].position;
- ERR_FAIL_COND(!states.has(p_name));
- ERR_FAIL_COND(states.has(p_new_name));
+ Map<StringName, AStarCost> cost_map;
- states[p_new_name] = states[p_name];
- states.erase(p_name);
+ List<int> open_list;
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_name) {
- transitions[i].from = p_new_name;
- }
+ //build open list
+ for (int i = 0; i < sm->transitions.size(); i++) {
+ if (sm->transitions[i].from == current) {
+ open_list.push_back(i);
+ float cost = sm->states[sm->transitions[i].to].position.distance_to(current_pos);
+ cost *= sm->transitions[i].transition->get_priority();
+ AStarCost ap;
+ ap.prev = current;
+ ap.distance = cost;
+ cost_map[sm->transitions[i].to] = ap;
- if (transitions[i].to == p_name) {
- transitions[i].to = p_new_name;
+ if (sm->transitions[i].to == p_travel) { //prematurely found it! :D
+ path.push_back(p_travel);
+ return true;
+ }
}
}
- if (start_node == p_name) {
- start_node = p_new_name;
- }
+ //begin astar
+ bool found_route = false;
+ while (!found_route) {
- if (end_node == p_name) {
- end_node = p_new_name;
- }
+ if (open_list.size() == 0) {
+ return false; //no path found
+ }
- if (playing && current == p_name) {
- current = p_new_name;
- }
+ //find the last cost transition
+ List<int>::Element *least_cost_transition = NULL;
+ float least_cost = 1e20;
- path.clear(); //clear path
-}
+ for (List<int>::Element *E = open_list.front(); E; E = E->next()) {
-void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
+ float cost = cost_map[sm->transitions[E->get()].to].distance;
+ cost += sm->states[sm->transitions[E->get()].to].position.distance_to(target_pos);
- List<StringName> nodes;
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
- nodes.push_back(E->key());
- }
- nodes.sort_custom<StringName::AlphCompare>();
+ if (cost < least_cost) {
+ least_cost_transition = E;
+ }
+ }
- for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
- r_nodes->push_back(E->get());
- }
-}
+ StringName transition_prev = sm->transitions[least_cost_transition->get()].from;
+ StringName transition = sm->transitions[least_cost_transition->get()].to;
-bool AnimationNodeStateMachine::has_transition(const StringName &p_from, const StringName &p_to) const {
+ for (int i = 0; i < sm->transitions.size(); i++) {
+ if (sm->transitions[i].from != transition || sm->transitions[i].to == transition_prev) {
+ continue; //not interested on those
+ }
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_from && transitions[i].to == p_to)
- return true;
- }
- return false;
-}
+ float distance = sm->states[sm->transitions[i].from].position.distance_to(sm->states[sm->transitions[i].to].position);
+ distance *= sm->transitions[i].transition->get_priority();
+ distance += cost_map[sm->transitions[i].from].distance;
-int AnimationNodeStateMachine::find_transition(const StringName &p_from, const StringName &p_to) const {
+ if (cost_map.has(sm->transitions[i].to)) {
+ //oh this was visited already, can we win the cost?
+ if (distance < cost_map[sm->transitions[i].to].distance) {
+ cost_map[sm->transitions[i].to].distance = distance;
+ cost_map[sm->transitions[i].to].prev = sm->transitions[i].from;
+ }
+ } else {
+ //add to open list
+ AStarCost ac;
+ ac.prev = sm->transitions[i].from;
+ ac.distance = distance;
+ cost_map[sm->transitions[i].to] = ac;
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_from && transitions[i].to == p_to)
- return i;
- }
- return -1;
-}
+ open_list.push_back(i);
-void AnimationNodeStateMachine::add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition) {
+ if (sm->transitions[i].to == p_travel) {
+ found_route = true;
+ break;
+ }
+ }
+ }
- ERR_FAIL_COND(p_from == p_to);
- ERR_FAIL_COND(!states.has(p_from));
- ERR_FAIL_COND(!states.has(p_to));
- ERR_FAIL_COND(p_transition.is_null());
+ if (found_route) {
+ break;
+ }
- for (int i = 0; i < transitions.size(); i++) {
- ERR_FAIL_COND(transitions[i].from == p_from && transitions[i].to == p_to);
+ open_list.erase(least_cost_transition);
}
- Transition tr;
- tr.from = p_from;
- tr.to = p_to;
- tr.transition = p_transition;
-
- transitions.push_back(tr);
-}
-
-Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_transition(int p_transition) const {
- ERR_FAIL_INDEX_V(p_transition, transitions.size(), Ref<AnimationNodeStateMachineTransition>());
- return transitions[p_transition].transition;
-}
-StringName AnimationNodeStateMachine::get_transition_from(int p_transition) const {
+ //make path
+ StringName at = p_travel;
+ while (at != current) {
+ path.push_back(at);
+ at = cost_map[at].prev;
+ }
- ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
- return transitions[p_transition].from;
-}
-StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const {
+ path.invert();
- ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
- return transitions[p_transition].to;
+ return true;
}
-int AnimationNodeStateMachine::get_transition_count() const {
-
- return transitions.size();
-}
-void AnimationNodeStateMachine::remove_transition(const StringName &p_from, const StringName &p_to) {
+float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, float p_time, bool p_seek) {
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_from && transitions[i].to == p_to) {
- transitions.remove(i);
- return;
+ //if not playing and it can restart, then restart
+ if (!playing && start_request == StringName()) {
+ if (!stop_request && sm->start_node) {
+ start(sm->start_node);
+ } else {
+ return 0;
}
}
- if (playing) {
- path.clear();
- }
-}
-
-void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) {
-
- transitions.remove(p_transition);
- if (playing) {
- path.clear();
+ if (playing && stop_request) {
+ stop_request = false;
+ playing = false;
+ return 0;
}
-}
-
-void AnimationNodeStateMachine::set_start_node(const StringName &p_node) {
-
- ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
- start_node = p_node;
-}
-
-String AnimationNodeStateMachine::get_start_node() const {
-
- return start_node;
-}
-
-void AnimationNodeStateMachine::set_end_node(const StringName &p_node) {
-
- ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
- end_node = p_node;
-}
-
-String AnimationNodeStateMachine::get_end_node() const {
-
- return end_node;
-}
-void AnimationNodeStateMachine::set_graph_offset(const Vector2 &p_offset) {
- graph_offset = p_offset;
-}
+ bool play_start = false;
-Vector2 AnimationNodeStateMachine::get_graph_offset() const {
- return graph_offset;
-}
+ if (start_request != StringName()) {
-float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
+ if (start_request_travel) {
+ if (!playing) {
+ start_request = StringName();
+ ERR_EXPLAIN("Can't travel to '" + String(start_request) + "' if state machine is not active.");
+ ERR_FAIL_V(0);
+ }
- //if not playing and it can restart, then restart
- if (!playing) {
- if (start_node) {
- start(start_node);
+ if (!_travel(sm, start_request)) {
+ //cant travel, then teleport
+ path.clear();
+ current = start_request;
+ }
} else {
- return 0;
+ path.clear();
+ current = start_request;
+ playing = true;
+ play_start = true;
}
+
+ start_request = StringName(); //clear start request
}
bool do_start = (p_seek && p_time == 0) || play_start || current == StringName();
if (do_start) {
- if (start_node != StringName() && p_seek && p_time == 0) {
- current = start_node;
+ if (sm->start_node != StringName() && p_seek && p_time == 0) {
+ current = sm->start_node;
}
- len_current = blend_node(states[current], 0, true, 1.0, FILTER_IGNORE, false);
+ len_current = sm->blend_node(current, sm->states[current].node, 0, true, 1.0, AnimationNode::FILTER_IGNORE, false);
pos_current = 0;
loops_current = 0;
play_start = false;
}
+ if (!sm->states.has(current)) {
+ playing = false; //current does not exist
+ current = StringName();
+ return 0;
+ }
float fade_blend = 1.0;
if (fading_from != StringName()) {
- if (!p_seek) {
- fading_pos += p_time;
- }
- fade_blend = MIN(1.0, fading_pos / fading_time);
- if (fade_blend >= 1.0) {
+ if (!sm->states.has(fading_from)) {
fading_from = StringName();
+ } else {
+ if (!p_seek) {
+ fading_pos += p_time;
+ }
+ fade_blend = MIN(1.0, fading_pos / fading_time);
+ if (fade_blend >= 1.0) {
+ fading_from = StringName();
+ }
}
}
- float rem = blend_node(states[current], p_time, p_seek, fade_blend, FILTER_IGNORE, false);
+ float rem = sm->blend_node(current, sm->states[current].node, p_time, p_seek, fade_blend, AnimationNode::FILTER_IGNORE, false);
if (fading_from != StringName()) {
- blend_node(states[fading_from], p_time, p_seek, 1.0 - fade_blend, FILTER_IGNORE, false);
+ sm->blend_node(current, sm->states[fading_from].node, p_time, p_seek, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, false);
}
//guess playback position
@@ -380,29 +399,39 @@ float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
if (path.size()) {
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == current && transitions[i].to == path[0]) {
- next_xfade = transitions[i].transition->get_xfade_time();
- switch_mode = transitions[i].transition->get_switch_mode();
+ for (int i = 0; i < sm->transitions.size(); i++) {
+ if (sm->transitions[i].from == current && sm->transitions[i].to == path[0]) {
+ next_xfade = sm->transitions[i].transition->get_xfade_time();
+ switch_mode = sm->transitions[i].transition->get_switch_mode();
next = path[0];
}
}
} else {
float priority_best = 1e20;
int auto_advance_to = -1;
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == current && transitions[i].transition->has_auto_advance()) {
+ for (int i = 0; i < sm->transitions.size(); i++) {
+
+ bool auto_advance = false;
+ if (sm->transitions[i].transition->has_auto_advance()) {
+ auto_advance = true;
+ }
+ StringName advance_condition_name = sm->transitions[i].transition->get_advance_condition_name();
+ if (advance_condition_name != StringName() && bool(sm->get_parameter(advance_condition_name))) {
+ auto_advance = true;
+ }
+
+ if (sm->transitions[i].from == current && auto_advance) {
- if (transitions[i].transition->get_priority() < priority_best) {
+ if (sm->transitions[i].transition->get_priority() < priority_best) {
auto_advance_to = i;
}
}
}
if (auto_advance_to != -1) {
- next = transitions[auto_advance_to].to;
- next_xfade = transitions[auto_advance_to].transition->get_xfade_time();
- switch_mode = transitions[auto_advance_to].transition->get_switch_mode();
+ next = sm->transitions[auto_advance_to].to;
+ next_xfade = sm->transitions[auto_advance_to].transition->get_xfade_time();
+ switch_mode = sm->transitions[auto_advance_to].transition->get_switch_mode();
}
}
@@ -437,12 +466,12 @@ float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
}
current = next;
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
- len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false);
+ len_current = sm->blend_node(current, sm->states[current].node, 0, true, 0, AnimationNode::FILTER_IGNORE, false);
pos_current = MIN(pos_current, len_current);
- blend_node(states[current], pos_current, true, 0, FILTER_IGNORE, false);
+ sm->blend_node(current, sm->states[current].node, pos_current, true, 0, AnimationNode::FILTER_IGNORE, false);
} else {
- len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false);
+ len_current = sm->blend_node(current, sm->states[current].node, 0, true, 0, AnimationNode::FILTER_IGNORE, false);
pos_current = 0;
}
@@ -453,169 +482,321 @@ float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
//compute time left for transitions by using the end node
- if (end_node != StringName() && end_node != current) {
+ if (sm->end_node != StringName() && sm->end_node != current) {
- rem = blend_node(states[end_node], 0, true, 0, FILTER_IGNORE, false);
+ rem = sm->blend_node(current, sm->states[sm->end_node].node, 0, true, 0, AnimationNode::FILTER_IGNORE, false);
}
return rem;
}
-bool AnimationNodeStateMachine::travel(const StringName &p_state) {
- ERR_FAIL_COND_V(!playing, false);
- ERR_FAIL_COND_V(!states.has(p_state), false);
- ERR_FAIL_COND_V(!states.has(current), false);
+void AnimationNodeStateMachinePlayback::_bind_methods() {
- path.clear(); //a new one will be needed
+ ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachinePlayback::travel);
+ ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachinePlayback::start);
+ ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop);
+ ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing);
+ ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node);
+ ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::get_travel_path);
+}
- if (current == p_state)
- return true; //nothing to do
+AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
+ set_local_to_scene(true); //only one per instanced scene
- loops_current = 0; // reset loops, so fade does not happen immediately
+ playing = false;
+ len_current = 0;
+ fading_time = 0;
+ stop_request = false;
+}
- Vector2 current_pos = states[current]->get_position();
- Vector2 target_pos = states[p_state]->get_position();
+///////////////////////////////////////////////////////
- Map<StringName, AStarCost> cost_map;
+void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::OBJECT, playback, PROPERTY_HINT_RESOURCE_TYPE, "AnimationNodeStateMachinePlayback", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ List<StringName> advance_conditions;
+ for (int i = 0; i < transitions.size(); i++) {
+ StringName ac = transitions[i].transition->get_advance_condition_name();
+ if (ac != StringName() && advance_conditions.find(ac) == NULL) {
+ advance_conditions.push_back(ac);
+ }
+ }
- List<int> open_list;
+ advance_conditions.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = advance_conditions.front(); E; E = E->next()) {
+ r_list->push_back(PropertyInfo(Variant::BOOL, E->get()));
+ }
+}
- //build open list
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == current) {
- open_list.push_back(i);
- float cost = states[transitions[i].to]->get_position().distance_to(current_pos);
- cost *= transitions[i].transition->get_priority();
- AStarCost ap;
- ap.prev = current;
- ap.distance = cost;
- cost_map[transitions[i].to] = ap;
+Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const {
- if (transitions[i].to == p_state) { //prematurely found it! :D
- path.push_back(p_state);
- return true;
- }
- }
+ if (p_parameter == playback) {
+ Ref<AnimationNodeStateMachinePlayback> p;
+ p.instance();
+ return p;
+ } else {
+ return false; //advance condition
}
+}
- //begin astar
- bool found_route = false;
- while (!found_route) {
+void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
- if (open_list.size() == 0) {
- return false; //no path found
+ ERR_FAIL_COND(states.has(p_name));
+ ERR_FAIL_COND(p_node.is_null());
+ ERR_FAIL_COND(String(p_name).find("/") != -1);
+
+ State state;
+ state.node = p_node;
+ state.position = p_position;
+
+ states[p_name] = state;
+
+ emit_changed();
+ emit_signal("tree_changed");
+
+ p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+}
+
+Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>());
+
+ return states[p_name].node;
+}
+
+StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const {
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
+ if (E->get().node == p_node) {
+ return E->key();
}
+ }
- //find the last cost transition
- List<int>::Element *least_cost_transition = NULL;
- float least_cost = 1e20;
+ ERR_FAIL_V(StringName());
+}
- for (List<int>::Element *E = open_list.front(); E; E = E->next()) {
+void AnimationNodeStateMachine::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ Vector<StringName> nodes;
- float cost = cost_map[transitions[E->get()].to].distance;
- cost += states[transitions[E->get()].to]->get_position().distance_to(target_pos);
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
+ nodes.push_back(E->key());
+ }
- if (cost < least_cost) {
- least_cost_transition = E;
- }
+ nodes.sort_custom<StringName::AlphCompare>();
+
+ for (int i = 0; i < nodes.size(); i++) {
+ ChildNode cn;
+ cn.name = nodes[i];
+ cn.node = states[cn.name].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
+bool AnimationNodeStateMachine::has_node(const StringName &p_name) const {
+ return states.has(p_name);
+}
+void AnimationNodeStateMachine::remove_node(const StringName &p_name) {
+
+ ERR_FAIL_COND(!states.has(p_name));
+
+ {
+ Ref<AnimationNode> node = states[p_name].node;
+ node->disconnect("tree_changed", this, "_tree_changed");
+ }
+
+ states.erase(p_name);
+ //path.erase(p_name);
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_name || transitions[i].to == p_name) {
+ transitions.write[i].transition->disconnect("advance_condition_changed", this, "_tree_changed");
+ transitions.remove(i);
+ i--;
}
+ }
- StringName transition_prev = transitions[least_cost_transition->get()].from;
- StringName transition = transitions[least_cost_transition->get()].to;
+ if (start_node == p_name) {
+ start_node = StringName();
+ }
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from != transition || transitions[i].to == transition_prev) {
- continue; //not interested on those
- }
+ if (end_node == p_name) {
+ end_node = StringName();
+ }
- float distance = states[transitions[i].from]->get_position().distance_to(states[transitions[i].to]->get_position());
- distance *= transitions[i].transition->get_priority();
- distance += cost_map[transitions[i].from].distance;
+ /*if (playing && current == p_name) {
+ stop();
+ }*/
- if (cost_map.has(transitions[i].to)) {
- //oh this was visited already, can we win the cost?
- if (distance < cost_map[transitions[i].to].distance) {
- cost_map[transitions[i].to].distance = distance;
- cost_map[transitions[i].to].prev = transitions[i].from;
- }
- } else {
- //add to open list
- AStarCost ac;
- ac.prev = transitions[i].from;
- ac.distance = distance;
- cost_map[transitions[i].to] = ac;
+ emit_changed();
+ emit_signal("tree_changed");
+}
- open_list.push_back(i);
+void AnimationNodeStateMachine::rename_node(const StringName &p_name, const StringName &p_new_name) {
- if (transitions[i].to == p_state) {
- found_route = true;
- break;
- }
- }
+ ERR_FAIL_COND(!states.has(p_name));
+ ERR_FAIL_COND(states.has(p_new_name));
+
+ states[p_new_name] = states[p_name];
+ states.erase(p_name);
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_name) {
+ transitions.write[i].from = p_new_name;
}
- if (found_route) {
- break;
+ if (transitions[i].to == p_name) {
+ transitions.write[i].to = p_new_name;
}
+ }
- open_list.erase(least_cost_transition);
+ if (start_node == p_name) {
+ start_node = p_new_name;
}
- //make path
- StringName at = p_state;
- while (at != current) {
- path.push_back(at);
- at = cost_map[at].prev;
+ if (end_node == p_name) {
+ end_node = p_new_name;
}
- path.invert();
+ /*if (playing && current == p_name) {
+ current = p_new_name;
+ }*/
- return true;
+ //path.clear(); //clear path
+ emit_signal("tree_changed");
}
-void AnimationNodeStateMachine::start(const StringName &p_state) {
+void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
+
+ List<StringName> nodes;
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
+ nodes.push_back(E->key());
+ }
+ nodes.sort_custom<StringName::AlphCompare>();
- ERR_FAIL_COND(!states.has(p_state));
- path.clear();
- current = p_state;
- playing = true;
- play_start = true;
+ for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
+ r_nodes->push_back(E->get());
+ }
}
-void AnimationNodeStateMachine::stop() {
- playing = false;
- play_start = false;
- current = StringName();
+
+bool AnimationNodeStateMachine::has_transition(const StringName &p_from, const StringName &p_to) const {
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_from && transitions[i].to == p_to)
+ return true;
+ }
+ return false;
}
-bool AnimationNodeStateMachine::is_playing() const {
- return playing;
+int AnimationNodeStateMachine::find_transition(const StringName &p_from, const StringName &p_to) const {
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_from && transitions[i].to == p_to)
+ return i;
+ }
+ return -1;
}
-StringName AnimationNodeStateMachine::get_current_node() const {
- if (!playing) {
- return StringName();
+
+void AnimationNodeStateMachine::add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition) {
+
+ ERR_FAIL_COND(p_from == p_to);
+ ERR_FAIL_COND(!states.has(p_from));
+ ERR_FAIL_COND(!states.has(p_to));
+ ERR_FAIL_COND(p_transition.is_null());
+
+ for (int i = 0; i < transitions.size(); i++) {
+ ERR_FAIL_COND(transitions[i].from == p_from && transitions[i].to == p_to);
}
- return current;
+ Transition tr;
+ tr.from = p_from;
+ tr.to = p_to;
+ tr.transition = p_transition;
+
+ tr.transition->connect("advance_condition_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+
+ transitions.push_back(tr);
+}
+
+Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_transition(int p_transition) const {
+ ERR_FAIL_INDEX_V(p_transition, transitions.size(), Ref<AnimationNodeStateMachineTransition>());
+ return transitions[p_transition].transition;
}
+StringName AnimationNodeStateMachine::get_transition_from(int p_transition) const {
+
+ ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
+ return transitions[p_transition].from;
+}
+StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const {
+
+ ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
+ return transitions[p_transition].to;
+}
+
+int AnimationNodeStateMachine::get_transition_count() const {
+
+ return transitions.size();
+}
+void AnimationNodeStateMachine::remove_transition(const StringName &p_from, const StringName &p_to) {
-StringName AnimationNodeStateMachine::get_blend_from_node() const {
- if (!playing) {
- return StringName();
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_from && transitions[i].to == p_to) {
+ transitions.write[i].transition->disconnect("advance_condition_changed", this, "_tree_changed");
+ transitions.remove(i);
+ return;
+ }
}
- return fading_from;
+ /*if (playing) {
+ path.clear();
+ }*/
}
-float AnimationNodeStateMachine::get_current_play_pos() const {
- return pos_current;
+void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) {
+
+ ERR_FAIL_INDEX(p_transition, transitions.size());
+ transitions.write[p_transition].transition->disconnect("advance_condition_changed", this, "_tree_changed");
+ transitions.remove(p_transition);
+ /*if (playing) {
+ path.clear();
+ }*/
}
-float AnimationNodeStateMachine::get_current_length() const {
- return len_current;
+
+void AnimationNodeStateMachine::set_start_node(const StringName &p_node) {
+
+ ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
+ start_node = p_node;
}
-Vector<StringName> AnimationNodeStateMachine::get_travel_path() const {
- return path;
+String AnimationNodeStateMachine::get_start_node() const {
+
+ return start_node;
+}
+
+void AnimationNodeStateMachine::set_end_node(const StringName &p_node) {
+
+ ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
+ end_node = p_node;
+}
+
+String AnimationNodeStateMachine::get_end_node() const {
+
+ return end_node;
+}
+
+void AnimationNodeStateMachine::set_graph_offset(const Vector2 &p_offset) {
+ graph_offset = p_offset;
+}
+
+Vector2 AnimationNodeStateMachine::get_graph_offset() const {
+ return graph_offset;
+}
+
+float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
+
+ Ref<AnimationNodeStateMachinePlayback> playback = get_parameter(this->playback);
+ ERR_FAIL_COND_V(playback.is_null(), 0.0);
+
+ return playback->process(this, p_time, p_seek);
}
+
String AnimationNodeStateMachine::get_caption() const {
return "StateMachine";
}
@@ -623,14 +804,8 @@ String AnimationNodeStateMachine::get_caption() const {
void AnimationNodeStateMachine::_notification(int p_what) {
}
-void AnimationNodeStateMachine::set_tree(AnimationTree *p_player) {
-
- AnimationNode::set_tree(p_player);
-
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
- Ref<AnimationRootNode> node = E->get();
- node->set_tree(p_player);
- }
+Ref<AnimationNode> AnimationNodeStateMachine::get_child_by_name(const StringName &p_name) {
+ return get_node(p_name);
}
bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_value) {
@@ -651,7 +826,7 @@ bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_
if (what == "position") {
if (states.has(node_name)) {
- states[node_name]->set_position(p_value);
+ states[node_name].position = p_value;
}
return true;
}
@@ -687,7 +862,7 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
if (what == "node") {
if (states.has(node_name)) {
- r_ret = states[node_name];
+ r_ret = states[node_name].node;
return true;
}
}
@@ -695,7 +870,7 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
if (what == "position") {
if (states.has(node_name)) {
- r_ret = states[node_name]->get_position();
+ r_ret = states[node_name].position;
return true;
}
}
@@ -727,14 +902,14 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
names.push_back(E->key());
}
names.sort_custom<StringName::AlphCompare>();
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
String name = E->get();
- p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
@@ -744,16 +919,34 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c
p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeStateMachine::set_node_position(const StringName &p_name, const Vector2 &p_position) {
+ ERR_FAIL_COND(!states.has(p_name));
+ states[p_name].position = p_position;
+}
+
+Vector2 AnimationNodeStateMachine::get_node_position(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!states.has(p_name), Vector2());
+ return states[p_name].position;
+}
+
+void AnimationNodeStateMachine::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
void AnimationNodeStateMachine::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeStateMachine::add_node);
+ ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeStateMachine::add_node, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node);
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeStateMachine::remove_node);
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeStateMachine::rename_node);
ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeStateMachine::has_node);
ClassDB::bind_method(D_METHOD("get_node_name", "node"), &AnimationNodeStateMachine::get_node_name);
- ClassDB::bind_method(D_METHOD("has_transition", "from", "to"), &AnimationNodeStateMachine::add_transition);
+ ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeStateMachine::set_node_position);
+ ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeStateMachine::get_node_position);
+
+ ClassDB::bind_method(D_METHOD("has_transition", "from", "to"), &AnimationNodeStateMachine::has_transition);
ClassDB::bind_method(D_METHOD("add_transition", "from", "to", "transition"), &AnimationNodeStateMachine::add_transition);
ClassDB::bind_method(D_METHOD("get_transition", "idx"), &AnimationNodeStateMachine::get_transition);
ClassDB::bind_method(D_METHOD("get_transition_from", "idx"), &AnimationNodeStateMachine::get_transition_from);
@@ -771,20 +964,10 @@ void AnimationNodeStateMachine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_graph_offset", "name"), &AnimationNodeStateMachine::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset);
- ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachine::travel);
- ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachine::start);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachine::stop);
- ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachine::is_playing);
- ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachine::get_current_node);
- ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachine::get_travel_path);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeStateMachine::_tree_changed);
}
AnimationNodeStateMachine::AnimationNodeStateMachine() {
- play_start = false;
-
- playing = false;
- len_current = 0;
-
- fading_time = 0;
+ playback = "playback";
}
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index e7357e09ea..a88b3eb482 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_node_state_machine.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 ANIMATION_NODE_STATE_MACHINE_H
#define ANIMATION_NODE_STATE_MACHINE_H
@@ -15,6 +45,8 @@ public:
private:
SwitchMode switch_mode;
bool auto_advance;
+ StringName advance_condition;
+ StringName advance_condition_name;
float xfade;
bool disabled;
int priority;
@@ -29,6 +61,11 @@ public:
void set_auto_advance(bool p_enable);
bool has_auto_advance() const;
+ void set_advance_condition(const StringName &p_condition);
+ StringName get_advance_condition() const;
+
+ StringName get_advance_condition_name() const;
+
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
@@ -43,39 +80,24 @@ public:
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode)
-class AnimationNodeStateMachine : public AnimationRootNode {
-
- GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
+class AnimationNodeStateMachine;
-private:
- Map<StringName, Ref<AnimationRootNode> > states;
+class AnimationNodeStateMachinePlayback : public Resource {
+ GDCLASS(AnimationNodeStateMachinePlayback, Resource);
- struct Transition {
-
- StringName from;
- StringName to;
- Ref<AnimationNodeStateMachineTransition> transition;
- };
+ friend class AnimationNodeStateMachine;
struct AStarCost {
float distance;
StringName prev;
};
- Vector<Transition> transitions;
-
float len_total;
float len_current;
float pos_current;
int loops_current;
- bool play_start;
- StringName start_node;
- StringName end_node;
-
- Vector2 graph_offset;
-
StringName current;
StringName fading_from;
@@ -85,6 +107,63 @@ private:
Vector<StringName> path;
bool playing;
+ StringName start_request;
+ bool start_request_travel;
+ bool stop_request;
+
+ bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
+
+ float process(AnimationNodeStateMachine *p_state_machine, float p_time, bool p_seek);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void travel(const StringName &p_state);
+ void start(const StringName &p_state);
+ void stop();
+ bool is_playing() const;
+ StringName get_current_node() const;
+ StringName get_blend_from_node() const;
+ Vector<StringName> get_travel_path() const;
+ float get_current_play_pos() const;
+ float get_current_length() const;
+
+ AnimationNodeStateMachinePlayback();
+};
+
+class AnimationNodeStateMachine : public AnimationRootNode {
+
+ GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
+
+private:
+ friend class AnimationNodeStateMachinePlayback;
+
+ struct State {
+ Ref<AnimationRootNode> node;
+ Vector2 position;
+ };
+
+ Map<StringName, State> states;
+
+ struct Transition {
+
+ StringName from;
+ StringName to;
+ Ref<AnimationNodeStateMachineTransition> transition;
+ };
+
+ Vector<Transition> transitions;
+
+ StringName playback;
+
+ StringName start_node;
+ StringName end_node;
+
+ Vector2 graph_offset;
+
+ void _tree_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -94,7 +173,10 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
- void add_node(const StringName &p_name, Ref<AnimationNode> p_node);
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
@@ -102,6 +184,11 @@ public:
StringName get_node_name(const Ref<AnimationNode> &p_node) const;
void get_node_list(List<StringName> *r_nodes) const;
+ void set_node_position(const StringName &p_name, const Vector2 &p_position);
+ Vector2 get_node_position(const StringName &p_name) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
+
bool has_transition(const StringName &p_from, const StringName &p_to) const;
int find_transition(const StringName &p_from, const StringName &p_to) const;
void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition);
@@ -124,17 +211,7 @@ public:
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;
- bool travel(const StringName &p_state);
- void start(const StringName &p_state);
- void stop();
- bool is_playing() const;
- StringName get_current_node() const;
- StringName get_blend_from_node() const;
- Vector<StringName> get_travel_path() const;
- float get_current_play_pos() const;
- float get_current_length() const;
-
- virtual void set_tree(AnimationTree *p_player);
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeStateMachine();
};
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 06aaeddf18..d8db1973d2 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -233,7 +233,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
for (int i = 0; i < a->get_track_count(); i++) {
- p_anim->node_cache[i] = NULL;
+ p_anim->node_cache.write[i] = NULL;
RES resource;
Vector<StringName> leftover_path;
Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path);
@@ -265,12 +265,12 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
if (node_cache_map.has(key)) {
- p_anim->node_cache[i] = &node_cache_map[key];
+ p_anim->node_cache.write[i] = &node_cache_map[key];
} else {
node_cache_map[key] = TrackNodeCache();
- p_anim->node_cache[i] = &node_cache_map[key];
+ p_anim->node_cache.write[i] = &node_cache_map[key];
p_anim->node_cache[i]->path = a->track_get_path(i);
p_anim->node_cache[i]->node = child;
p_anim->node_cache[i]->resource = resource;
@@ -331,11 +331,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
if (!p_anim->node_cache[i]->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
TrackNodeCache::BezierAnim ba;
- String path = leftover_path[leftover_path.size() - 1];
- Vector<String> index = path.split(".");
- for (int j = 0; j < index.size(); j++) {
- ba.bezier_property.push_back(index[j]);
- }
+ ba.bezier_property = leftover_path;
ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
ba.owner = p_anim->node_cache[i];
@@ -419,14 +415,26 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
pa->capture = pa->object->get_indexed(pa->subpath);
}
- if (a->track_get_key_count(i) == 0)
+ int key_count = a->track_get_key_count(i);
+ if (key_count == 0)
continue; //eeh not worth it
float first_key_time = a->track_get_key_time(i, 0);
+ float transition = 1.0;
+ int first_key = 0;
+
+ if (first_key_time == 0.0) {
+ //ignore, use for transition
+ if (key_count == 1)
+ continue; //with one key we cant do anything
+ transition = a->track_get_key_transition(i, 0);
+ first_key_time = a->track_get_key_time(i, 1);
+ first_key = 1;
+ }
if (p_time < first_key_time) {
- float c = p_time / first_key_time;
- Variant first_value = a->track_get_key_value(i, 0);
+ float c = Math::ease(p_time / first_key_time, transition);
+ Variant first_value = a->track_get_key_value(i, first_key);
Variant interp_value;
Variant::interpolate(pa->capture, first_value, c, interp_value);
@@ -537,6 +545,12 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
int s = params.size();
ERR_CONTINUE(s > VARIANT_ARG_MAX);
+#ifdef DEBUG_ENABLED
+ if (!nc->node->has_method(method)) {
+ ERR_PRINTS("Invalid method call '" + method + "'. '" + a->get_name() + "' at node '" + get_path() + "'.");
+ }
+#endif
+
if (can_call) {
MessageQueue::get_singleton()->push_call(
nc->node,
@@ -648,7 +662,22 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->audio_start = p_time;
}
} else if (nc->audio_playing) {
- if (nc->audio_start > p_time || (nc->audio_len > 0 && p_time - nc->audio_start < nc->audio_len)) {
+
+ bool loop = a->has_loop();
+
+ bool stop = false;
+
+ if (!loop && p_time < nc->audio_start) {
+ stop = true;
+ } else if (nc->audio_len > 0) {
+ float len = nc->audio_start > p_time ? (a->get_length() - nc->audio_start) + p_time : p_time - nc->audio_start;
+
+ if (len > nc->audio_len) {
+ stop = true;
+ }
+ }
+
+ if (stop) {
//time to stop
nc->node->call("stop");
nc->audio_playing = false;
@@ -931,8 +960,6 @@ Error AnimationPlayer::add_animation(const StringName &p_name, const Ref<Animati
ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER);
- //print_line("Add anim: "+String(p_name)+" name: "+p_animation->get_name());
-
if (animation_set.has(p_name)) {
_unref_anim(animation_set[p_name].animation);
@@ -1615,7 +1642,7 @@ void AnimationPlayer::_bind_methods() {
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::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "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::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");
@@ -1627,6 +1654,7 @@ void AnimationPlayer::_bind_methods() {
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
+ BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
}
AnimationPlayer::AnimationPlayer() {
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 49c73e54ad..f50b2454ec 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -65,6 +65,7 @@ public:
enum AnimationProcessMode {
ANIMATION_PROCESS_PHYSICS,
ANIMATION_PROCESS_IDLE,
+ ANIMATION_PROCESS_MANUAL,
};
private:
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 62f2726f75..9b06d538e9 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_tree.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 "animation_tree.h"
#include "animation_blend_tree.h"
#include "core/method_bind_ext.gen.inc"
@@ -5,6 +35,34 @@
#include "scene/scene_string_names.h"
#include "servers/audio/audio_stream.h"
+void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
+}
+
+Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
+ return Variant();
+}
+
+void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND(!state);
+ ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
+ ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
+ StringName path = state->tree->property_parent_map[base_path][p_name];
+
+ state->tree->property_map[path] = p_value;
+}
+
+Variant AnimationNode::get_parameter(const StringName &p_name) const {
+ ERR_FAIL_COND_V(!state, Variant());
+ ERR_FAIL_COND_V(!state->tree->property_parent_map.has(base_path), Variant());
+ ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name), Variant());
+
+ StringName path = state->tree->property_parent_map[base_path][p_name];
+ return state->tree->property_map[path];
+}
+
+void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
+}
+
void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) {
ERR_FAIL_COND(!state);
@@ -14,8 +72,8 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
if (animation.is_null()) {
- Ref<AnimationNodeBlendTree> btree = get_parent();
- if (btree.is_valid()) {
+ AnimationNodeBlendTree *btree = Object::cast_to<AnimationNodeBlendTree>(parent);
+ if (btree) {
String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this));
make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation));
} else {
@@ -37,10 +95,20 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
state->animation_states.push_back(anim_state);
}
-float AnimationNode::_pre_process(State *p_state, float p_time, bool p_seek) {
+float AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections) {
+
+ base_path = p_base_path;
+ parent = p_parent;
+ connections = p_connections;
state = p_state;
+
float t = process(p_time, p_seek);
+
state = NULL;
+ parent = NULL;
+ base_path = StringName();
+ connections.clear();
+
return t;
}
@@ -56,39 +124,39 @@ void AnimationNode::make_invalid(const String &p_reason) {
float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
ERR_FAIL_COND_V(!state, 0);
- ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs
- Ref<AnimationNodeBlendTree> tree = get_parent();
+ AnimationNodeBlendTree *blend_tree = Object::cast_to<AnimationNodeBlendTree>(parent);
+ ERR_FAIL_COND_V(!blend_tree, 0);
+
+ StringName node_name = connections[p_input];
- if (!tree.is_valid() && get_tree()->get_tree_root().ptr() != this) {
- make_invalid(RTR("Can't blend input because node is not in a tree"));
+ if (!blend_tree->has_node(node_name)) {
+ String name = blend_tree->get_node_name(Ref<AnimationNode>(this));
+ make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
return 0;
}
- ERR_FAIL_COND_V(!tree.is_valid(), 0); //should not happen
+ Ref<AnimationNode> node = blend_tree->get_node(node_name);
- StringName anim_name = inputs[p_input].connected_to;
+ //inputs.write[p_input].last_pass = state->last_pass;
+ float activity = 0;
+ float ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), NULL, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity);
- Ref<AnimationNode> node = tree->get_node(anim_name);
+ Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
- if (node.is_null()) {
-
- String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
- make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
- return 0;
+ if (activity_ptr && p_input < activity_ptr->size()) {
+ activity_ptr->write[p_input].last_pass = state->last_pass;
+ activity_ptr->write[p_input].activity = activity;
}
-
- inputs[p_input].last_pass = state->last_pass;
-
- return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs[p_input].activity);
+ return ret;
}
-float AnimationNode::blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
+float AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
- return _blend_node(p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
+ return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
}
-float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
+float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
ERR_FAIL_COND_V(!state, 0);
@@ -189,7 +257,19 @@ float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p
if (!p_seek && p_optimize && !any_valid) //pointless to go on, all are zero
return 0;
- return p_node->_pre_process(state, p_time, p_seek);
+ String new_path;
+ AnimationNode *new_parent;
+
+ //this is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations
+ if (p_new_parent) {
+ new_parent = p_new_parent;
+ new_path = String(base_path) + String(p_subpath) + "/";
+ } else {
+ ERR_FAIL_COND_V(!parent, 0);
+ new_parent = parent;
+ new_path = String(parent->base_path) + String(p_subpath) + "/";
+ }
+ return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_connections);
}
int AnimationNode::get_input_count() const {
@@ -201,29 +281,6 @@ String AnimationNode::get_input_name(int p_input) {
return inputs[p_input].name;
}
-float AnimationNode::get_input_activity(int p_input) const {
-
- ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
- if (!get_tree())
- return 0;
-
- if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) {
- return 0;
- }
- return inputs[p_input].activity;
-}
-StringName AnimationNode::get_input_connection(int p_input) {
-
- ERR_FAIL_INDEX_V(p_input, inputs.size(), StringName());
- return inputs[p_input].connected_to;
-}
-
-void AnimationNode::set_input_connection(int p_input, const StringName &p_connection) {
-
- ERR_FAIL_INDEX(p_input, inputs.size());
- inputs[p_input].connected_to = p_connection;
-}
-
String AnimationNode::get_caption() const {
if (get_script_instance()) {
@@ -239,8 +296,6 @@ void AnimationNode::add_input(const String &p_name) {
Input input;
ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1);
input.name = p_name;
- input.activity = 0;
- input.last_pass = 0;
inputs.push_back(input);
emit_changed();
}
@@ -248,7 +303,7 @@ void AnimationNode::add_input(const String &p_name) {
void AnimationNode::set_input_name(int p_input, const String &p_name) {
ERR_FAIL_INDEX(p_input, inputs.size());
ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1);
- inputs[p_input].name = p_name;
+ inputs.write[p_input].name = p_name;
emit_changed();
}
@@ -258,35 +313,6 @@ void AnimationNode::remove_input(int p_index) {
emit_changed();
}
-void AnimationNode::_set_parent(Object *p_parent) {
- set_parent(Object::cast_to<AnimationNode>(p_parent));
-}
-
-void AnimationNode::set_parent(AnimationNode *p_parent) {
- parent = p_parent; //do not use ref because parent contains children
- if (get_script_instance()) {
- get_script_instance()->call("_parent_set", p_parent);
- }
-}
-
-Ref<AnimationNode> AnimationNode::get_parent() const {
- if (parent) {
- return Ref<AnimationNode>(parent);
- }
-
- return Ref<AnimationNode>();
-}
-
-AnimationTree *AnimationNode::get_tree() const {
-
- return player;
-}
-
-AnimationPlayer *AnimationNode::get_player() const {
- ERR_FAIL_COND_V(!state, NULL);
- return state->player;
-}
-
float AnimationNode::process(float p_time, bool p_seek) {
if (get_script_instance()) {
@@ -320,22 +346,6 @@ bool AnimationNode::has_filter() const {
return false;
}
-void AnimationNode::set_position(const Vector2 &p_position) {
- position = p_position;
-}
-
-Vector2 AnimationNode::get_position() const {
- return position;
-}
-
-void AnimationNode::set_tree(AnimationTree *p_player) {
-
- if (player != NULL && p_player == NULL) {
- emit_signal("removed_from_graph");
- }
- player = p_player;
-}
-
Array AnimationNode::_get_filters() const {
Array paths;
@@ -361,12 +371,14 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
}
}
+Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
+ return Ref<AnimationNode>();
+}
+
void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
- ClassDB::bind_method(D_METHOD("get_input_connection", "input"), &AnimationNode::get_input_connection);
- ClassDB::bind_method(D_METHOD("get_input_activity", "input"), &AnimationNode::get_input_activity);
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
@@ -377,19 +389,15 @@ void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled);
ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled);
- ClassDB::bind_method(D_METHOD("set_position", "position"), &AnimationNode::set_position);
- ClassDB::bind_method(D_METHOD("get_position"), &AnimationNode::get_position);
-
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation);
- ClassDB::bind_method(D_METHOD("blend_node", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("set_parent", "parent"), &AnimationNode::_set_parent);
- ClassDB::bind_method(D_METHOD("get_parent"), &AnimationNode::get_parent);
- ClassDB::bind_method(D_METHOD("get_tree"), &AnimationNode::get_tree);
+ ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
+ ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
@@ -397,9 +405,11 @@ void AnimationNode::_bind_methods() {
BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek")));
BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter"));
- BIND_VMETHOD(MethodInfo("_parent_set", PropertyInfo(Variant::OBJECT, "parent")));
ADD_SIGNAL(MethodInfo("removed_from_graph"));
+
+ ADD_SIGNAL(MethodInfo("tree_changed"));
+
BIND_ENUM_CONSTANT(FILTER_IGNORE);
BIND_ENUM_CONSTANT(FILTER_PASS);
BIND_ENUM_CONSTANT(FILTER_STOP);
@@ -410,8 +420,6 @@ AnimationNode::AnimationNode() {
state = NULL;
parent = NULL;
- player = NULL;
- set_local_to_scene(true);
filter_enabled = false;
}
@@ -420,18 +428,17 @@ AnimationNode::AnimationNode() {
void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
if (root.is_valid()) {
- root->set_tree(NULL);
- }
- if (p_root.is_valid()) {
- ERR_EXPLAIN("root node already set to another player");
- ERR_FAIL_COND(p_root->player);
+ root->disconnect("tree_changed", this, "_tree_changed");
}
+
root = p_root;
if (root.is_valid()) {
- root->set_tree(this);
+ root->connect("tree_changed", this, "_tree_changed");
}
+ properties_dirty = true;
+
update_configuration_warning();
}
@@ -699,7 +706,10 @@ void AnimationTree::_clear_caches() {
void AnimationTree::_process_graph(float p_delta) {
+ _update_properties(); //if properties need updating, update them
+
//check all tracks, see if they need modification
+
root_motion_transform = Transform();
if (!root.is_valid()) {
@@ -718,6 +728,28 @@ void AnimationTree::_process_graph(float p_delta) {
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
+ ObjectID current_animation_player = 0;
+
+ if (player) {
+ current_animation_player = player->get_instance_id();
+ }
+
+ if (last_animation_player != current_animation_player) {
+
+ if (last_animation_player) {
+ Object *old_player = ObjectDB::get_instance(last_animation_player);
+ if (old_player) {
+ old_player->disconnect("caches_cleared", this, "_clear_caches");
+ }
+ }
+
+ if (player) {
+ player->connect("caches_cleared", this, "_clear_caches");
+ }
+
+ last_animation_player = current_animation_player;
+ }
+
if (!player) {
ERR_PRINT("AnimationTree: path points to a node not an AnimationPlayer, disabling playback");
set_active(false);
@@ -741,6 +773,7 @@ void AnimationTree::_process_graph(float p_delta) {
state.valid = true;
state.player = player;
state.last_pass = process_pass;
+ state.tree = this;
// root source blends
@@ -757,11 +790,11 @@ void AnimationTree::_process_graph(float p_delta) {
if (started) {
//if started, seek
- root->_pre_process(&state, 0, true);
+ root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, 0, true, Vector<StringName>());
started = false;
}
- root->_pre_process(&state, p_delta, false);
+ root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, p_delta, false, Vector<StringName>());
}
if (!state.valid) {
@@ -813,6 +846,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->process_pass = process_pass;
t->loc = Vector3();
t->rot = Quat();
+ t->rot_blend_accum = 0;
t->scale = Vector3();
}
@@ -876,7 +910,14 @@ void AnimationTree::_process_graph(float p_delta) {
continue;
t->loc = t->loc.linear_interpolate(loc, blend);
- t->rot = t->rot.slerp(rot, blend);
+ if (t->rot_blend_accum == 0) {
+ t->rot = rot;
+ t->rot_blend_accum = blend;
+ } else {
+ float rot_total = t->rot_blend_accum + blend;
+ t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized();
+ t->rot_blend_accum = rot_total;
+ }
t->scale = t->scale.linear_interpolate(scale, blend);
}
@@ -1033,7 +1074,22 @@ void AnimationTree::_process_graph(float p_delta) {
t->start = time;
}
} else if (t->playing) {
- if (t->start > time || (t->len > 0 && time - t->start < t->len)) {
+
+ bool loop = a->has_loop();
+
+ bool stop = false;
+
+ if (!loop && time < t->start) {
+ stop = true;
+ } else if (t->len > 0) {
+ float len = t->start > time ? (a->get_length() - t->start) + time : time - t->start;
+
+ if (len > t->len) {
+ stop = true;
+ }
+ }
+
+ if (stop) {
//time to stop
t->object->call("stop");
t->playing = false;
@@ -1042,6 +1098,12 @@ void AnimationTree::_process_graph(float p_delta) {
}
}
+ float db = Math::linear2db(MAX(blend, 0.00001));
+ if (t->object->has_method("set_unit_db")) {
+ t->object->call("set_unit_db", db);
+ } else {
+ t->object->call("set_volume_db", db);
+ }
} break;
case Animation::TYPE_ANIMATION: {
@@ -1170,6 +1232,11 @@ void AnimationTree::_process_graph(float p_delta) {
}
}
+void AnimationTree::advance(float p_time) {
+
+ _process_graph(p_time);
+}
+
void AnimationTree::_notification(int p_what) {
if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) {
@@ -1182,6 +1249,13 @@ void AnimationTree::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
_clear_caches();
+ if (last_animation_player) {
+
+ Object *old_player = ObjectDB::get_instance(last_animation_player);
+ if (old_player) {
+ old_player->disconnect("caches_cleared", this, "_clear_caches");
+ }
+ }
}
}
@@ -1263,6 +1337,148 @@ Transform AnimationTree::get_root_motion_transform() const {
return root_motion_transform;
}
+void AnimationTree::_tree_changed() {
+ if (properties_dirty) {
+ return;
+ }
+
+ call_deferred("_update_properties");
+ properties_dirty = true;
+}
+
+void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node) {
+
+ if (!property_parent_map.has(p_base_path)) {
+ property_parent_map[p_base_path] = HashMap<StringName, StringName>();
+ }
+
+ if (node->get_input_count() && !input_activity_map.has(p_base_path)) {
+
+ Vector<Activity> activity;
+ for (int i = 0; i < node->get_input_count(); i++) {
+ Activity a;
+ a.last_pass = 0;
+ activity.push_back(a);
+ }
+ input_activity_map[p_base_path] = activity;
+ input_activity_map_get[String(p_base_path).substr(0, String(p_base_path).length() - 1)] = &input_activity_map[p_base_path];
+ }
+
+ List<PropertyInfo> plist;
+ node->get_parameter_list(&plist);
+ for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
+ PropertyInfo pinfo = E->get();
+
+ StringName key = pinfo.name;
+
+ if (!property_map.has(p_base_path + key)) {
+ property_map[p_base_path + key] = node->get_parameter_default_value(key);
+ }
+
+ property_parent_map[p_base_path][key] = p_base_path + key;
+
+ pinfo.name = p_base_path + key;
+ properties.push_back(pinfo);
+ }
+
+ List<AnimationNode::ChildNode> children;
+ node->get_child_nodes(&children);
+
+ for (List<AnimationNode::ChildNode>::Element *E = children.front(); E; E = E->next()) {
+ _update_properties_for_node(p_base_path + E->get().name + "/", E->get().node);
+ }
+}
+
+void AnimationTree::_update_properties() {
+ if (!properties_dirty) {
+ return;
+ }
+
+ properties.clear();
+ property_parent_map.clear();
+ input_activity_map.clear();
+ input_activity_map_get.clear();
+
+ if (root.is_valid()) {
+ _update_properties_for_node(SceneStringNames::get_singleton()->parameters_base_path, root);
+ }
+
+ properties_dirty = false;
+
+ _change_notify();
+}
+
+bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
+ if (properties_dirty) {
+ _update_properties();
+ }
+
+ if (property_map.has(p_name)) {
+ property_map[p_name] = p_value;
+#ifdef TOOLS_ENABLED
+ _change_notify(p_name.operator String().utf8().get_data());
+#endif
+ return true;
+ }
+
+ return false;
+}
+
+bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
+ if (properties_dirty) {
+ const_cast<AnimationTree *>(this)->_update_properties();
+ }
+
+ if (property_map.has(p_name)) {
+ r_ret = property_map[p_name];
+ return true;
+ }
+
+ return false;
+}
+void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (properties_dirty) {
+ const_cast<AnimationTree *>(this)->_update_properties();
+ }
+
+ for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ p_list->push_back(E->get());
+ }
+}
+
+void AnimationTree::rename_parameter(const String &p_base, const String &p_new_base) {
+
+ //rename values first
+ for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ if (E->get().name.begins_with(p_base)) {
+ String new_name = E->get().name.replace_first(p_base, p_new_base);
+ property_map[new_name] = property_map[E->get().name];
+ }
+ }
+
+ //update tree second
+ properties_dirty = true;
+ _update_properties();
+}
+
+float AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const {
+
+ if (!input_activity_map_get.has(p_path)) {
+ return 0;
+ }
+ const Vector<Activity> *activity = input_activity_map_get[p_path];
+
+ if (!activity || p_connection < 0 || p_connection >= activity->size()) {
+ return 0;
+ }
+
+ if ((*activity)[p_connection].last_pass != process_pass) {
+ return 0;
+ }
+
+ return (*activity)[p_connection].activity;
+}
+
void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationTree::set_active);
ClassDB::bind_method(D_METHOD("is_active"), &AnimationTree::is_active);
@@ -1279,14 +1495,28 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track);
ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track);
+ ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform);
+
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationTree::_tree_changed);
+ ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
+
+ ClassDB::bind_method(D_METHOD("rename_parameter", "old_name", "new_name"), &AnimationTree::rename_parameter);
+
+ ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance);
+
ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed);
+ ClassDB::bind_method(D_METHOD("_clear_caches"), &AnimationTree::_clear_caches);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player"), "set_animation_player", "get_animation_player");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode");
ADD_GROUP("Root Motion", "root_motion_");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");
+
+ BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
+ BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
+ BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
}
AnimationTree::AnimationTree() {
@@ -1296,10 +1526,9 @@ AnimationTree::AnimationTree() {
cache_valid = false;
setup_pass = 1;
started = true;
+ properties_dirty = true;
+ last_animation_player = 0;
}
AnimationTree::~AnimationTree() {
- if (root.is_valid()) {
- root->player = NULL;
- }
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 41d67118c1..cda7f8ae74 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* animation_tree.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 ANIMATION_GRAPH_PLAYER_H
#define ANIMATION_GRAPH_PLAYER_H
@@ -23,9 +53,6 @@ public:
struct Input {
String name;
- StringName connected_to;
- float activity;
- uint64_t last_pass;
};
Vector<Input> inputs;
@@ -51,30 +78,33 @@ public:
List<AnimationState> animation_states;
bool valid;
AnimationPlayer *player;
+ AnimationTree *tree;
String invalid_reasons;
uint64_t last_pass;
};
Vector<float> blends;
State *state;
- float _pre_process(State *p_state, float p_time, bool p_seek);
+
+ float _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections);
void _pre_update_animations(HashMap<NodePath, int> *track_map);
- Vector2 position;
+ //all this is temporary
+ StringName base_path;
+ Vector<StringName> connections;
AnimationNode *parent;
- AnimationTree *player;
-
- float _blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
HashMap<NodePath, bool> filter;
bool filter_enabled;
Array _get_filters() const;
void _set_filters(const Array &p_filters);
+ friend class AnimationNodeBlendTree;
+ float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
protected:
void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend);
- float blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
+ float blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
float blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
void make_invalid(const String &p_reason);
@@ -85,20 +115,24 @@ protected:
void _set_parent(Object *p_parent);
public:
- void set_parent(AnimationNode *p_parent);
- Ref<AnimationNode> get_parent() const;
- virtual void set_tree(AnimationTree *p_player);
- AnimationTree *get_tree() const;
- AnimationPlayer *get_player() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ void set_parameter(const StringName &p_name, const Variant &p_value);
+ Variant get_parameter(const StringName &p_name) const;
+
+ struct ChildNode {
+ StringName name;
+ Ref<AnimationNode> node;
+ };
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;
int get_input_count() const;
String get_input_name(int p_input);
- StringName get_input_connection(int p_input);
- void set_input_connection(int p_input, const StringName &p_connection);
- float get_input_activity(int p_input) const;
void add_input(const String &p_name);
void set_input_name(int p_input, const String &p_name);
@@ -112,8 +146,7 @@ public:
virtual bool has_filter() const;
- void set_position(const Vector2 &p_position);
- Vector2 get_position() const;
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNode();
};
@@ -133,6 +166,7 @@ public:
enum AnimationProcessMode {
ANIMATION_PROCESS_PHYSICS,
ANIMATION_PROCESS_IDLE,
+ ANIMATION_PROCESS_MANUAL,
};
private:
@@ -161,6 +195,7 @@ private:
int bone_idx;
Vector3 loc;
Quat rot;
+ float rot_blend_accum;
Vector3 scale;
TrackCacheTransform() {
@@ -243,7 +278,31 @@ private:
NodePath root_motion_track;
Transform root_motion_transform;
+ friend class AnimationNode;
+ bool properties_dirty;
+ void _tree_changed();
+ void _update_properties();
+ List<PropertyInfo> properties;
+ HashMap<StringName, HashMap<StringName, StringName> > property_parent_map;
+ HashMap<StringName, Variant> property_map;
+
+ struct Activity {
+ uint64_t last_pass;
+ float activity;
+ };
+
+ HashMap<StringName, Vector<Activity> > input_activity_map;
+ HashMap<StringName, Vector<Activity> *> input_activity_map_get;
+
+ void _update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node);
+
+ ObjectID last_animation_player;
+
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);
static void _bind_methods();
@@ -270,6 +329,11 @@ public:
Transform get_root_motion_transform() const;
+ float get_connection_activity(const StringName &p_path, int p_connection) const;
+ void advance(float p_time);
+
+ void rename_parameter(const String &p_base, const String &p_new_base);
+
uint64_t get_last_process_pass() const;
AnimationTree();
~AnimationTree();
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index 143684bdf9..179f5d9698 100644
--- a/scene/animation/animation_tree_player.cpp
+++ b/scene/animation/animation_tree_player.cpp
@@ -1152,7 +1152,7 @@ void AnimationTreePlayer::transition_node_set_input_auto_advance(const StringNam
GET_NODE(NODE_TRANSITION, TransitionNode);
ERR_FAIL_INDEX(p_input, n->input_data.size());
- n->input_data[p_input].auto_advance = p_auto_advance;
+ n->input_data.write[p_input].auto_advance = p_auto_advance;
}
void AnimationTreePlayer::transition_node_set_xfade_time(const StringName &p_node, float p_time) {
@@ -1365,7 +1365,7 @@ void AnimationTreePlayer::remove_node(const StringName &p_node) {
for (int i = 0; i < nb->inputs.size(); i++) {
if (nb->inputs[i].node == p_node)
- nb->inputs[i].node = StringName();
+ nb->inputs.write[i].node = StringName();
}
}
@@ -1426,11 +1426,11 @@ Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const Str
for (int i = 0; i < nb->inputs.size(); i++) {
if (nb->inputs[i].node == p_src_node)
- nb->inputs[i].node = StringName();
+ nb->inputs.write[i].node = StringName();
}
}
- dst->inputs[p_dst_input].node = p_src_node;
+ dst->inputs.write[p_dst_input].node = p_src_node;
_clear_cycle_test();
@@ -1463,7 +1463,7 @@ void AnimationTreePlayer::disconnect_nodes(const StringName &p_node, int p_input
NodeBase *dst = node_map[p_node];
ERR_FAIL_INDEX(p_input, dst->inputs.size());
- dst->inputs[p_input].node = StringName();
+ dst->inputs.write[p_input].node = StringName();
last_error = CONNECT_INCOMPLETE;
dirty_caches = true;
}
@@ -1703,7 +1703,7 @@ Error AnimationTreePlayer::node_rename(const StringName &p_node, const StringNam
for (int i = 0; i < nb->inputs.size(); i++) {
if (nb->inputs[i].node == p_node) {
- nb->inputs[i].node = p_new_name;
+ nb->inputs.write[i].node = p_new_name;
}
}
}
@@ -1814,7 +1814,7 @@ void AnimationTreePlayer::_bind_methods() {
ADD_GROUP("Playback", "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::NODE_PATH, "master_player"), "set_master_player", "get_master_player");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "master_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_master_player", "get_master_player");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "base_path"), "set_base_path", "get_base_path");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index 1625b80db4..098bd05e9a 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* root_motion_view.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 "root_motion_view.h"
#include "scene/animation/animation_tree.h"
#include "scene/resources/material.h"
@@ -37,6 +67,14 @@ float RootMotionView::get_radius() const {
return radius;
}
+void RootMotionView::set_zero_y(bool p_zero_y) {
+ zero_y = p_zero_y;
+}
+
+bool RootMotionView::get_zero_y() const {
+ return zero_y;
+}
+
void RootMotionView::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
@@ -77,9 +115,11 @@ void RootMotionView::_notification(int p_what) {
transform.orthonormalize(); //dont want scale, too imprecise
transform.affine_invert();
- accumulated = accumulated * transform;
+ accumulated = transform * accumulated;
accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size);
- accumulated.origin.y = Math::fposmod(accumulated.origin.y, cell_size);
+ if (zero_y) {
+ accumulated.origin.y = 0;
+ }
accumulated.origin.z = Math::fposmod(accumulated.origin.z, cell_size);
VS::get_singleton()->immediate_clear(immediate);
@@ -142,13 +182,18 @@ void RootMotionView::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "size"), &RootMotionView::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &RootMotionView::get_radius);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_path"), "set_animation_path", "get_animation_path");
+ ClassDB::bind_method(D_METHOD("set_zero_y", "enable"), &RootMotionView::set_zero_y);
+ ClassDB::bind_method(D_METHOD("get_zero_y"), &RootMotionView::get_zero_y);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationTree"), "set_animation_path", "get_animation_path");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell_size", PROPERTY_HINT_RANGE, "0.1,16,0.01,or_greater"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,16,0.01,or_greater"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "zero_y"), "set_zero_y", "get_zero_y");
}
RootMotionView::RootMotionView() {
+ zero_y = true;
radius = 10;
cell_size = 1;
set_process_internal(true);
diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h
index 65e9ff480b..5198ab21aa 100644
--- a/scene/animation/root_motion_view.h
+++ b/scene/animation/root_motion_view.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* root_motion_view.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 ROOT_MOTION_VIEW_H
#define ROOT_MOTION_VIEW_H
@@ -13,6 +43,7 @@ public:
bool use_in_game;
Color color;
bool first;
+ bool zero_y;
Transform accumulated;
@@ -33,6 +64,9 @@ public:
void set_radius(float p_radius);
float get_radius() const;
+ void set_zero_y(bool p_zero_y);
+ bool get_zero_y() const;
+
virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
new file mode 100644
index 0000000000..69975e6195
--- /dev/null
+++ b/scene/animation/skeleton_ik.cpp
@@ -0,0 +1,561 @@
+/*************************************************************************/
+/* skeleton_ik.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. */
+/*************************************************************************/
+
+/**
+ * @author AndreaCatania
+ */
+
+#include "skeleton_ik.h"
+
+#ifndef _3D_DISABLED
+
+FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) {
+ for (int i = childs.size() - 1; 0 <= i; --i) {
+ if (p_bone_id == childs[i].bone) {
+ return &childs.write[i];
+ }
+ }
+ return NULL;
+}
+
+FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(const BoneId p_bone_id) {
+ const int infant_child_id = childs.size();
+ childs.resize(infant_child_id + 1);
+ childs.write[infant_child_id].bone = p_bone_id;
+ childs.write[infant_child_id].parent_item = this;
+ return &childs.write[infant_child_id];
+}
+
+/// Build a chain that starts from the root to tip
+bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) {
+
+ ERR_FAIL_COND_V(-1 == p_task->root_bone, false);
+
+ Chain &chain(p_task->chain);
+
+ chain.tips.resize(p_task->end_effectors.size());
+ chain.chain_root.bone = p_task->root_bone;
+ chain.chain_root.initial_transform = p_task->skeleton->get_bone_global_pose(chain.chain_root.bone);
+ chain.chain_root.current_pos = chain.chain_root.initial_transform.origin;
+ chain.chain_root.pb = p_task->skeleton->get_physical_bone(chain.chain_root.bone);
+ chain.middle_chain_item = NULL;
+
+ // Holds all IDs that are composing a single chain in reverse order
+ Vector<BoneId> chain_ids;
+ // This is used to know the chain size
+ int sub_chain_size;
+ // Resize only one time in order to fit all joints for performance reason
+ chain_ids.resize(p_task->skeleton->get_bone_count());
+
+ for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) {
+
+ const EndEffector *ee(&p_task->end_effectors[x]);
+ ERR_FAIL_COND_V(p_task->root_bone >= ee->tip_bone, false);
+ ERR_FAIL_INDEX_V(ee->tip_bone, p_task->skeleton->get_bone_count(), false);
+
+ sub_chain_size = 0;
+ // Picks all IDs that composing a single chain in reverse order (except the root)
+ BoneId chain_sub_tip(ee->tip_bone);
+ while (chain_sub_tip > p_task->root_bone) {
+
+ chain_ids.write[sub_chain_size++] = chain_sub_tip;
+ chain_sub_tip = p_task->skeleton->get_bone_parent(chain_sub_tip);
+ }
+
+ BoneId middle_chain_item_id = (((float)sub_chain_size) * 0.5);
+
+ // Build chain by reading chain ids in reverse order
+ // For each chain item id will be created a ChainItem if doesn't exists
+ ChainItem *sub_chain(&chain.chain_root);
+ for (int i = sub_chain_size - 1; 0 <= i; --i) {
+
+ ChainItem *child_ci(sub_chain->find_child(chain_ids[i]));
+ if (!child_ci) {
+
+ child_ci = sub_chain->add_child(chain_ids[i]);
+
+ child_ci->pb = p_task->skeleton->get_physical_bone(child_ci->bone);
+
+ child_ci->initial_transform = p_task->skeleton->get_bone_global_pose(child_ci->bone);
+ child_ci->current_pos = child_ci->initial_transform.origin;
+
+ if (child_ci->parent_item) {
+ child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length();
+ }
+ }
+
+ sub_chain = child_ci;
+
+ if (middle_chain_item_id == i) {
+ chain.middle_chain_item = child_ci;
+ }
+ }
+
+ if (!middle_chain_item_id)
+ chain.middle_chain_item = NULL;
+
+ // Initialize current tip
+ chain.tips.write[x].chain_item = sub_chain;
+ chain.tips.write[x].end_effector = ee;
+
+ if (p_force_simple_chain) {
+ // NOTE:
+ // This is an "hack" that force to create only one tip per chain since the solver of multi tip (end effector)
+ // is not yet created.
+ // Remove this code when this is done
+ break;
+ }
+ }
+ return true;
+}
+
+void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_chain_item) {
+
+ if (!p_chain_item)
+ return;
+
+ p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone);
+ p_chain_item->current_pos = p_chain_item->initial_transform.origin;
+
+ for (int i = p_chain_item->childs.size() - 1; 0 <= i; --i) {
+ update_chain(p_sk, &p_chain_item->childs.write[i]);
+ }
+}
+
+void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) {
+
+ real_t distance_to_goal(1e4);
+ real_t previous_distance_to_goal(0);
+ int can_solve(p_task->max_iterations);
+ while (distance_to_goal > p_task->min_distance && Math::abs(previous_distance_to_goal - distance_to_goal) > 0.005 && can_solve) {
+ previous_distance_to_goal = distance_to_goal;
+ --can_solve;
+
+ solve_simple_backwards(p_task->chain, p_solve_magnet);
+ solve_simple_forwards(p_task->chain, p_solve_magnet);
+
+ distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length();
+ }
+}
+
+void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve_magnet) {
+
+ if (p_solve_magnet && !r_chain.middle_chain_item) {
+ return;
+ }
+
+ Vector3 goal;
+ ChainItem *sub_chain_tip;
+ if (p_solve_magnet) {
+ goal = r_chain.magnet_position;
+ sub_chain_tip = r_chain.middle_chain_item;
+ } else {
+ goal = r_chain.tips[0].end_effector->goal_transform.origin;
+ sub_chain_tip = r_chain.tips[0].chain_item;
+ }
+
+ while (sub_chain_tip) {
+ sub_chain_tip->current_pos = goal;
+
+ if (sub_chain_tip->parent_item) {
+ // Not yet in the chain root
+ // So calculate next goal location
+
+ const Vector3 look_parent((sub_chain_tip->parent_item->current_pos - sub_chain_tip->current_pos).normalized());
+ goal = sub_chain_tip->current_pos + (look_parent * sub_chain_tip->length);
+
+ // [TODO] Constraints goes here
+ }
+
+ sub_chain_tip = sub_chain_tip->parent_item;
+ }
+}
+
+void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) {
+
+ if (p_solve_magnet && !r_chain.middle_chain_item) {
+ return;
+ }
+
+ ChainItem *sub_chain_root(&r_chain.chain_root);
+ Vector3 origin(r_chain.chain_root.initial_transform.origin);
+
+ while (sub_chain_root) { // Reach the tip
+ sub_chain_root->current_pos = origin;
+
+ if (!sub_chain_root->childs.empty()) {
+
+ ChainItem &child(sub_chain_root->childs.write[0]);
+
+ // Is not tip
+ // So calculate next origin location
+
+ // Look child
+ sub_chain_root->current_ori = (child.current_pos - sub_chain_root->current_pos).normalized();
+ origin = sub_chain_root->current_pos + (sub_chain_root->current_ori * child.length);
+
+ // [TODO] Constraints goes here
+
+ if (p_solve_magnet && sub_chain_root == r_chain.middle_chain_item) {
+ // In case of magnet solving this is the tip
+ sub_chain_root = NULL;
+ } else {
+ sub_chain_root = &child;
+ }
+ } else {
+
+ // Is tip
+ sub_chain_root = NULL;
+ }
+ }
+}
+
+FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) {
+
+ FabrikInverseKinematic::EndEffector ee;
+ ee.tip_bone = tip_bone;
+
+ Task *task(memnew(Task));
+ task->skeleton = p_sk;
+ task->root_bone = root_bone;
+ task->end_effectors.push_back(ee);
+ task->goal_global_transform = goal_transform;
+
+ if (!build_chain(task)) {
+ free_task(task);
+ return NULL;
+ }
+
+ return task;
+}
+
+void FabrikInverseKinematic::free_task(Task *p_task) {
+ if (p_task)
+ memdelete(p_task);
+}
+
+void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) {
+ p_task->goal_global_transform = p_goal;
+}
+
+void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta) {
+
+ if (blending_delta >= 0.99f) {
+ // Update the end_effector (local transform) without blending
+ p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform;
+ } else {
+
+ // End effector in local transform
+ const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors.write[0].tip_bone));
+
+ // Update the end_effector (local transform) by blending with current pose
+ p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta);
+ }
+}
+
+void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position) {
+
+ if (blending_delta <= 0.01f) {
+ return; // Skip solving
+ }
+
+ make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse().scaled(p_task->skeleton->get_global_transform().get_basis().get_scale()), blending_delta);
+
+ update_chain(p_task->skeleton, &p_task->chain.chain_root);
+
+ if (p_use_magnet && p_task->chain.middle_chain_item) {
+ p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.linear_interpolate(p_magnet_position, blending_delta);
+ solve_simple(p_task, true);
+ }
+ solve_simple(p_task, false);
+
+ // Assign new bone position.
+ ChainItem *ci(&p_task->chain.chain_root);
+ while (ci) {
+ Transform new_bone_pose(ci->initial_transform);
+ new_bone_pose.origin = ci->current_pos;
+
+ if (!ci->childs.empty()) {
+
+ /// Rotate basis
+ const Vector3 initial_ori((ci->childs[0].initial_transform.origin - ci->initial_transform.origin).normalized());
+ const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
+
+ if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
+ const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
+ new_bone_pose.basis.rotate(rot_axis, rot_angle);
+ }
+ } else {
+ // Set target orientation to tip
+ new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
+ }
+
+ p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose);
+
+ if (!ci->childs.empty())
+ ci = &ci->childs.write[0];
+ else
+ ci = NULL;
+ }
+}
+
+void SkeletonIK::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "root_bone" || property.name == "tip_bone") {
+
+ if (skeleton) {
+
+ String names;
+ for (int i = 0; i < skeleton->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += skeleton->get_bone_name(i);
+ }
+
+ property.hint = PROPERTY_HINT_ENUM;
+ property.hint_string = names;
+ } else {
+
+ property.hint = PROPERTY_HINT_NONE;
+ property.hint_string = "";
+ }
+ }
+}
+
+void SkeletonIK::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_root_bone", "root_bone"), &SkeletonIK::set_root_bone);
+ ClassDB::bind_method(D_METHOD("get_root_bone"), &SkeletonIK::get_root_bone);
+
+ ClassDB::bind_method(D_METHOD("set_tip_bone", "tip_bone"), &SkeletonIK::set_tip_bone);
+ ClassDB::bind_method(D_METHOD("get_tip_bone"), &SkeletonIK::get_tip_bone);
+
+ ClassDB::bind_method(D_METHOD("set_interpolation", "interpolation"), &SkeletonIK::set_interpolation);
+ ClassDB::bind_method(D_METHOD("get_interpolation"), &SkeletonIK::get_interpolation);
+
+ ClassDB::bind_method(D_METHOD("set_target_transform", "target"), &SkeletonIK::set_target_transform);
+ ClassDB::bind_method(D_METHOD("get_target_transform"), &SkeletonIK::get_target_transform);
+
+ ClassDB::bind_method(D_METHOD("set_target_node", "node"), &SkeletonIK::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonIK::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_use_magnet", "use"), &SkeletonIK::set_use_magnet);
+ ClassDB::bind_method(D_METHOD("is_using_magnet"), &SkeletonIK::is_using_magnet);
+
+ ClassDB::bind_method(D_METHOD("set_magnet_position", "local_position"), &SkeletonIK::set_magnet_position);
+ ClassDB::bind_method(D_METHOD("get_magnet_position"), &SkeletonIK::get_magnet_position);
+
+ ClassDB::bind_method(D_METHOD("get_parent_skeleton"), &SkeletonIK::get_parent_skeleton);
+ ClassDB::bind_method(D_METHOD("is_running"), &SkeletonIK::is_running);
+
+ ClassDB::bind_method(D_METHOD("set_min_distance", "min_distance"), &SkeletonIK::set_min_distance);
+ ClassDB::bind_method(D_METHOD("get_min_distance"), &SkeletonIK::get_min_distance);
+
+ ClassDB::bind_method(D_METHOD("set_max_iterations", "iterations"), &SkeletonIK::set_max_iterations);
+ ClassDB::bind_method(D_METHOD("get_max_iterations"), &SkeletonIK::get_max_iterations);
+
+ ClassDB::bind_method(D_METHOD("start", "one_time"), &SkeletonIK::start, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("stop"), &SkeletonIK::stop);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_bone"), "set_root_bone", "get_root_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tip_bone"), "set_tip_bone", "get_tip_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node"), "set_target_node", "get_target_node");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_distance"), "set_min_distance", "get_min_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_iterations"), "set_max_iterations", "get_max_iterations");
+}
+
+void SkeletonIK::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ skeleton = Object::cast_to<Skeleton>(get_parent());
+ reload_chain();
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+
+ if (target_node_override)
+ reload_goal();
+
+ _solve_chain();
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ reload_chain();
+ } break;
+ }
+}
+
+SkeletonIK::SkeletonIK() :
+ Node(),
+ interpolation(1),
+ skeleton(NULL),
+ target_node_override(NULL),
+ use_magnet(false),
+ min_distance(0.01),
+ max_iterations(10),
+ task(NULL) {
+
+ set_process_priority(1);
+}
+
+SkeletonIK::~SkeletonIK() {
+ FabrikInverseKinematic::free_task(task);
+ task = NULL;
+}
+
+void SkeletonIK::set_root_bone(const StringName &p_root_bone) {
+ root_bone = p_root_bone;
+ reload_chain();
+}
+
+StringName SkeletonIK::get_root_bone() const {
+ return root_bone;
+}
+
+void SkeletonIK::set_tip_bone(const StringName &p_tip_bone) {
+ tip_bone = p_tip_bone;
+ reload_chain();
+}
+
+StringName SkeletonIK::get_tip_bone() const {
+ return tip_bone;
+}
+
+void SkeletonIK::set_interpolation(real_t p_interpolation) {
+ interpolation = p_interpolation;
+}
+
+real_t SkeletonIK::get_interpolation() const {
+ return interpolation;
+}
+
+void SkeletonIK::set_target_transform(const Transform &p_target) {
+ target = p_target;
+ reload_goal();
+}
+
+const Transform &SkeletonIK::get_target_transform() const {
+ return target;
+}
+
+void SkeletonIK::set_target_node(const NodePath &p_node) {
+ target_node_path_override = p_node;
+ target_node_override = NULL;
+ reload_goal();
+}
+
+NodePath SkeletonIK::get_target_node() {
+ return target_node_path_override;
+}
+
+void SkeletonIK::set_use_magnet(bool p_use) {
+ use_magnet = p_use;
+}
+
+bool SkeletonIK::is_using_magnet() const {
+ return use_magnet;
+}
+
+void SkeletonIK::set_magnet_position(const Vector3 &p_local_position) {
+ magnet_position = p_local_position;
+}
+
+const Vector3 &SkeletonIK::get_magnet_position() const {
+ return magnet_position;
+}
+
+void SkeletonIK::set_min_distance(real_t p_min_distance) {
+ min_distance = p_min_distance;
+}
+
+void SkeletonIK::set_max_iterations(int p_iterations) {
+ max_iterations = p_iterations;
+}
+
+bool SkeletonIK::is_running() {
+ return is_processing_internal();
+}
+
+void SkeletonIK::start(bool p_one_time) {
+ if (p_one_time) {
+ set_process_internal(false);
+ _solve_chain();
+ } else {
+ set_process_internal(true);
+ }
+}
+
+void SkeletonIK::stop() {
+ set_process_internal(false);
+}
+
+Transform SkeletonIK::_get_target_transform() {
+
+ if (!target_node_override && !target_node_path_override.is_empty())
+ target_node_override = Object::cast_to<Spatial>(get_node(target_node_path_override));
+
+ if (target_node_override)
+ return target_node_override->get_global_transform();
+ else
+ return target;
+}
+
+void SkeletonIK::reload_chain() {
+
+ FabrikInverseKinematic::free_task(task);
+ task = NULL;
+
+ if (!skeleton)
+ return;
+
+ task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform());
+ if (task) {
+ task->max_iterations = max_iterations;
+ task->min_distance = min_distance;
+ }
+}
+
+void SkeletonIK::reload_goal() {
+ if (!task)
+ return;
+
+ FabrikInverseKinematic::set_goal(task, _get_target_transform());
+}
+
+void SkeletonIK::_solve_chain() {
+ if (!task)
+ return;
+ FabrikInverseKinematic::solve(task, interpolation, use_magnet, magnet_position);
+}
+
+#endif // _3D_DISABLED
diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h
new file mode 100644
index 0000000000..202d6959bb
--- /dev/null
+++ b/scene/animation/skeleton_ik.h
@@ -0,0 +1,216 @@
+/*************************************************************************/
+/* skeleton_ik.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_IK_H
+#define SKELETON_IK_H
+
+#ifndef _3D_DISABLED
+
+/**
+ * @author AndreaCatania
+ */
+
+#include "core/math/transform.h"
+#include "scene/3d/skeleton.h"
+
+class FabrikInverseKinematic {
+
+ struct EndEffector {
+ BoneId tip_bone;
+ Transform goal_transform;
+ };
+
+ struct ChainItem {
+
+ Vector<ChainItem> childs;
+ ChainItem *parent_item;
+
+ // Bone info
+ BoneId bone;
+ PhysicalBone *pb;
+
+ real_t length;
+ /// Positions relative to root bone
+ Transform initial_transform;
+ Vector3 current_pos;
+ // Direction from this bone to child
+ Vector3 current_ori;
+
+ ChainItem() :
+ parent_item(NULL),
+ bone(-1),
+ pb(NULL),
+ length(0) {}
+
+ ChainItem *find_child(const BoneId p_bone_id);
+ ChainItem *add_child(const BoneId p_bone_id);
+ };
+
+ struct ChainTip {
+ ChainItem *chain_item;
+ const EndEffector *end_effector;
+
+ ChainTip() :
+ chain_item(NULL),
+ end_effector(NULL) {}
+
+ ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) :
+ chain_item(p_chain_item),
+ end_effector(p_end_effector) {}
+
+ ChainTip(const ChainTip &p_other_ct) :
+ chain_item(p_other_ct.chain_item),
+ end_effector(p_other_ct.end_effector) {}
+ };
+
+ struct Chain {
+ ChainItem chain_root;
+ ChainItem *middle_chain_item;
+ Vector<ChainTip> tips;
+ Vector3 magnet_position;
+ };
+
+public:
+ struct Task : public RID_Data {
+ RID self;
+ Skeleton *skeleton;
+
+ Chain chain;
+
+ // Settings
+ real_t min_distance;
+ int max_iterations;
+
+ // Bone data
+ BoneId root_bone;
+ Vector<EndEffector> end_effectors;
+
+ Transform goal_global_transform;
+
+ Task() :
+ skeleton(NULL),
+ min_distance(0.01),
+ max_iterations(10),
+ root_bone(-1) {}
+ };
+
+private:
+ /// Init a chain that starts from the root to tip
+ static bool build_chain(Task *p_task, bool p_force_simple_chain = true);
+
+ static void update_chain(const Skeleton *p_sk, ChainItem *p_chain_item);
+
+ static void solve_simple(Task *p_task, bool p_solve_magnet);
+ /// Special solvers that solve only chains with one end effector
+ static void solve_simple_backwards(Chain &r_chain, bool p_solve_magnet);
+ static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet);
+
+public:
+ static Task *create_simple_task(Skeleton *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform);
+ static void free_task(Task *p_task);
+ // The goal of chain should be always in local space
+ static void set_goal(Task *p_task, const Transform &p_goal);
+ static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta);
+ static void solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position);
+};
+
+class SkeletonIK : public Node {
+ GDCLASS(SkeletonIK, Node);
+
+ StringName root_bone;
+ StringName tip_bone;
+ real_t interpolation;
+ Transform target;
+ NodePath target_node_path_override;
+ bool use_magnet;
+ Vector3 magnet_position;
+
+ real_t min_distance;
+ int max_iterations;
+
+ Skeleton *skeleton;
+ Spatial *target_node_override;
+ FabrikInverseKinematic::Task *task;
+
+protected:
+ virtual void
+ _validate_property(PropertyInfo &property) const;
+
+ static void _bind_methods();
+ virtual void _notification(int p_notification);
+
+public:
+ SkeletonIK();
+ virtual ~SkeletonIK();
+
+ void set_root_bone(const StringName &p_root_bone);
+ StringName get_root_bone() const;
+
+ void set_tip_bone(const StringName &p_tip_bone);
+ StringName get_tip_bone() const;
+
+ void set_interpolation(real_t p_interpolation);
+ real_t get_interpolation() const;
+
+ void set_target_transform(const Transform &p_target);
+ const Transform &get_target_transform() const;
+
+ void set_target_node(const NodePath &p_node);
+ NodePath get_target_node();
+
+ void set_use_magnet(bool p_use);
+ bool is_using_magnet() const;
+
+ void set_magnet_position(const Vector3 &p_constraint);
+ const Vector3 &get_magnet_position() const;
+
+ void set_min_distance(real_t p_min_distance);
+ real_t get_min_distance() const { return min_distance; }
+
+ void set_max_iterations(int p_iterations);
+ int get_max_iterations() const { return max_iterations; }
+
+ Skeleton *get_parent_skeleton() const { return skeleton; }
+
+ bool is_running();
+
+ void start(bool p_one_time = false);
+ void stop();
+
+private:
+ Transform _get_target_transform();
+ void reload_chain();
+ void reload_goal();
+ void _solve_chain();
+};
+
+#endif // _3D_DISABLED
+
+#endif // SKELETON_IK_H
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 9f7503577b..58be636e44 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -150,7 +150,7 @@ void Tween::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
- if (!processing) {
+ if (!is_active()) {
//make sure that a previous process state was not saved
//only process if "processing" is set
set_physics_process_internal(false);
@@ -164,7 +164,7 @@ void Tween::_notification(int p_what) {
if (tween_process_mode == TWEEN_PROCESS_PHYSICS)
break;
- if (processing)
+ if (is_active())
_tween_process(get_process_delta_time());
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -172,7 +172,7 @@ void Tween::_notification(int p_what) {
if (tween_process_mode == TWEEN_PROCESS_IDLE)
break;
- if (processing)
+ if (is_active())
_tween_process(get_physics_process_delta_time());
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -201,11 +201,10 @@ void Tween::_bind_methods() {
ClassDB::bind_method(D_METHOD("reset_all"), &Tween::reset_all);
ClassDB::bind_method(D_METHOD("stop", "object", "key"), &Tween::stop, DEFVAL(""));
ClassDB::bind_method(D_METHOD("stop_all"), &Tween::stop_all);
- ClassDB::bind_method(D_METHOD("is_stopped"), &Tween::is_stopped);
ClassDB::bind_method(D_METHOD("resume", "object", "key"), &Tween::resume, DEFVAL(""));
ClassDB::bind_method(D_METHOD("resume_all"), &Tween::resume_all);
ClassDB::bind_method(D_METHOD("remove", "object", "key"), &Tween::remove, DEFVAL(""));
- ClassDB::bind_method(D_METHOD("_remove", "object", "key", "first_only"), &Tween::_remove);
+ ClassDB::bind_method(D_METHOD("_remove_by_uid", "uid"), &Tween::_remove_by_uid);
ClassDB::bind_method(D_METHOD("remove_all"), &Tween::remove_all);
ClassDB::bind_method(D_METHOD("seek", "time"), &Tween::seek);
ClassDB::bind_method(D_METHOD("tell"), &Tween::tell);
@@ -522,8 +521,8 @@ void Tween::_tween_process(float p_delta) {
pending_update++;
// if repeat and all interpolates was finished then reset all interpolates
+ bool all_finished = true;
if (repeat) {
- bool all_finished = true;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -539,9 +538,12 @@ void Tween::_tween_process(float p_delta) {
reset_all();
}
+ all_finished = true;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
InterpolateData &data = E->get();
+ all_finished = all_finished && data.finish;
+
if (!data.active || data.finish)
continue;
@@ -555,8 +557,8 @@ void Tween::_tween_process(float p_delta) {
continue;
else if (prev_delaying) {
- emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false));
_apply_tween_value(data, data.initial_val);
+ emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false));
}
if (data.elapsed > (data.delay + data.duration)) {
@@ -603,32 +605,29 @@ void Tween::_tween_process(float p_delta) {
}
} 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);
+ emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result);
}
if (data.finish) {
_apply_tween_value(data, data.final_val);
+ data.elapsed = 0;
emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false));
// not repeat mode, remove completed action
if (!repeat)
- call_deferred("_remove", object, NodePath(Vector<StringName>(), data.key, false), true);
- }
+ call_deferred("_remove_by_uid", data.uid);
+ } else if (!repeat)
+ all_finished = all_finished && data.finish;
}
pending_update--;
+
+ if (all_finished)
+ set_active(false);
}
void Tween::set_tween_process_mode(TweenProcessMode p_mode) {
- if (tween_process_mode == p_mode)
- return;
-
- bool pr = processing;
- if (pr)
- _set_process(false);
tween_process_mode = p_mode;
- if (pr)
- _set_process(true);
}
Tween::TweenProcessMode Tween::get_tween_process_mode() const {
@@ -636,32 +635,21 @@ Tween::TweenProcessMode Tween::get_tween_process_mode() const {
return tween_process_mode;
}
-void Tween::_set_process(bool p_process, bool p_force) {
-
- if (processing == p_process && !p_force)
- return;
-
- switch (tween_process_mode) {
-
- case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_process && active); break;
- case TWEEN_PROCESS_IDLE: set_process_internal(p_process && active); break;
- }
-
- processing = p_process;
-}
-
bool Tween::is_active() const {
- return active;
+ return is_processing_internal() || is_physics_processing_internal();
}
void Tween::set_active(bool p_active) {
- if (active == p_active)
+ if (is_active() == p_active)
return;
- active = p_active;
- _set_process(processing, true);
+ switch (tween_process_mode) {
+
+ case TWEEN_PROCESS_IDLE: set_process_internal(p_active); break;
+ case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_active); break;
+ }
}
bool Tween::is_repeat() const {
@@ -687,7 +675,6 @@ float Tween::get_speed_scale() const {
bool Tween::start() {
set_active(true);
- _set_process(true);
return true;
}
@@ -744,14 +731,9 @@ bool Tween::stop(Object *p_object, StringName p_key) {
return true;
}
-bool Tween::is_stopped() const {
- return tell() >= get_runtime();
-}
-
bool Tween::stop_all() {
set_active(false);
- _set_process(false);
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -766,7 +748,6 @@ bool Tween::stop_all() {
bool Tween::resume(Object *p_object, StringName p_key) {
set_active(true);
- _set_process(true);
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -785,7 +766,6 @@ bool Tween::resume(Object *p_object, StringName p_key) {
bool Tween::resume_all() {
set_active(true);
- _set_process(true);
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -798,15 +778,9 @@ bool Tween::resume_all() {
}
bool Tween::remove(Object *p_object, StringName p_key) {
- _remove(p_object, p_key, false);
- return true;
-}
-
-void Tween::_remove(Object *p_object, StringName p_key, bool first_only) {
-
if (pending_update != 0) {
- call_deferred("_remove", p_object, p_key, first_only);
- return;
+ call_deferred("remove", p_object, p_key);
+ return true;
}
List<List<InterpolateData>::Element *> for_removal;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -817,14 +791,33 @@ void Tween::_remove(Object *p_object, StringName p_key, bool first_only) {
continue;
if (object == p_object && (data.concatenated_key == p_key || p_key == "")) {
for_removal.push_back(E);
- if (first_only) {
- break;
- }
}
}
for (List<List<InterpolateData>::Element *>::Element *E = for_removal.front(); E; E = E->next()) {
interpolates.erase(E->get());
}
+ return true;
+}
+
+void Tween::_remove_by_uid(int uid) {
+ if (pending_update != 0) {
+ call_deferred("_remove_by_uid", uid);
+ return;
+ }
+
+ for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
+ if (uid == E->get().uid) {
+ E->erase();
+ break;
+ }
+ }
+}
+
+void Tween::_push_interpolate_data(InterpolateData &p_data) {
+ pending_update++;
+ p_data.uid = ++uid;
+ interpolates.push_back(p_data);
+ pending_update--;
}
bool Tween::remove_all() {
@@ -834,8 +827,8 @@ bool Tween::remove_all() {
return true;
}
set_active(false);
- _set_process(false);
interpolates.clear();
+ uid = 0;
return true;
}
@@ -1048,7 +1041,7 @@ bool Tween::interpolate_property(Object *p_object, NodePath p_property, Variant
if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
return false;
- interpolates.push_back(data);
+ _push_interpolate_data(data);
return true;
}
@@ -1091,7 +1084,7 @@ bool Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_
if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
return false;
- interpolates.push_back(data);
+ _push_interpolate_data(data);
return true;
}
@@ -1143,9 +1136,7 @@ bool Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_c
data.arg[3] = p_arg4;
data.arg[4] = p_arg5;
- pending_update++;
- interpolates.push_back(data);
- pending_update--;
+ _push_interpolate_data(data);
return true;
}
@@ -1196,9 +1187,7 @@ bool Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, S
data.arg[3] = p_arg4;
data.arg[4] = p_arg5;
- pending_update++;
- interpolates.push_back(data);
- pending_update--;
+ _push_interpolate_data(data);
return true;
}
@@ -1253,7 +1242,7 @@ bool Tween::follow_property(Object *p_object, NodePath p_property, Variant p_ini
data.ease_type = p_ease_type;
data.delay = p_delay;
- interpolates.push_back(data);
+ _push_interpolate_data(data);
return true;
}
@@ -1304,7 +1293,7 @@ bool Tween::follow_method(Object *p_object, StringName p_method, Variant p_initi
data.ease_type = p_ease_type;
data.delay = p_delay;
- interpolates.push_back(data);
+ _push_interpolate_data(data);
return true;
}
@@ -1362,7 +1351,7 @@ bool Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_
if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
return false;
- interpolates.push_back(data);
+ _push_interpolate_data(data);
return true;
}
@@ -1417,7 +1406,7 @@ bool Tween::targeting_method(Object *p_object, StringName p_method, Object *p_in
if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
return false;
- interpolates.push_back(data);
+ _push_interpolate_data(data);
return true;
}
@@ -1425,11 +1414,10 @@ Tween::Tween() {
//String autoplay;
tween_process_mode = TWEEN_PROCESS_IDLE;
- processing = false;
- active = false;
repeat = false;
speed_scale = 1;
pending_update = 0;
+ uid = 0;
}
Tween::~Tween() {
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 36094bf294..aa47c00717 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -100,15 +100,15 @@ private:
real_t delay;
int args;
Variant arg[5];
+ int uid;
};
String autoplay;
TweenProcessMode tween_process_mode;
- bool processing;
- bool active;
bool repeat;
float speed_scale;
mutable int pending_update;
+ int uid;
List<InterpolateData> interpolates;
@@ -133,8 +133,8 @@ private:
bool _apply_tween_value(InterpolateData &p_data, Variant &value);
void _tween_process(float p_delta);
- void _set_process(bool p_process, bool p_force = false);
- void _remove(Object *p_object, StringName p_key, bool first_only);
+ void _remove_by_uid(int uid);
+ void _push_interpolate_data(InterpolateData &p_data);
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -162,7 +162,6 @@ public:
bool reset_all();
bool stop(Object *p_object, StringName p_key);
bool stop_all();
- bool is_stopped() const;
bool resume(Object *p_object, StringName p_key);
bool resume_all();
bool remove(Object *p_object, StringName p_key);
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp
index 408c00334a..7a9f2bd8d0 100644
--- a/scene/audio/audio_player.cpp
+++ b/scene/audio/audio_player.cpp
@@ -41,10 +41,10 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
int buffer_size = mix_buffer.size();
if (p_fadeout) {
- buffer_size = MIN(buffer_size, 16); //short fadeout ramp
+ // Short fadeout ramp
+ buffer_size = MIN(buffer_size, 128);
}
- //mix
stream_playback->mix(buffer, pitch_scale, buffer_size);
//multiply volume interpolating to avoid clicks if this changes
@@ -56,6 +56,7 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
buffer[i] *= vol;
vol += vol_inc;
}
+
//set volume for next mix
mix_volume_db = target_volume;
@@ -90,11 +91,14 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
void AudioStreamPlayer::_mix_audio() {
- if (!stream_playback.is_valid()) {
+ if (!stream_playback.is_valid() || !active)
return;
- }
- if (!active) {
+ if (stream_paused) {
+ if (stream_paused_fade) {
+ _mix_internal(true);
+ stream_paused_fade = false;
+ }
return;
}
@@ -135,6 +139,17 @@ void AudioStreamPlayer::_notification(int p_what) {
AudioServer::get_singleton()->remove_callback(_mix_audios, this);
}
+
+ if (p_what == NOTIFICATION_PAUSED) {
+ if (!can_process()) {
+ // Node can't process so we start fading out to silence
+ set_stream_paused(true);
+ }
+ }
+
+ if (p_what == NOTIFICATION_UNPAUSED) {
+ set_stream_paused(false);
+ }
}
void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
@@ -159,7 +174,6 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
if (p_stream.is_valid() && stream_playback.is_null()) {
stream.unref();
- ERR_FAIL_COND(stream_playback.is_null());
}
}
@@ -178,6 +192,7 @@ float AudioStreamPlayer::get_volume_db() const {
}
void AudioStreamPlayer::set_pitch_scale(float p_pitch_scale) {
+ ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
}
float AudioStreamPlayer::get_pitch_scale() const {
@@ -275,6 +290,19 @@ bool AudioStreamPlayer::_is_active() const {
return active;
}
+void AudioStreamPlayer::set_stream_paused(bool p_pause) {
+
+ if (p_pause != stream_paused) {
+ stream_paused = p_pause;
+ stream_paused_fade = p_pause ? true : false;
+ }
+}
+
+bool AudioStreamPlayer::get_stream_paused() const {
+
+ return stream_paused;
+}
+
void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
if (property.name == "bus") {
@@ -328,11 +356,15 @@ void AudioStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer::_bus_layout_changed);
+ ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer::set_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer::get_stream_paused);
+
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::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_target", PROPERTY_HINT_ENUM, "Stereo,Surround,Center"), "set_mix_target", "get_mix_target");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
@@ -351,6 +383,8 @@ AudioStreamPlayer::AudioStreamPlayer() {
autoplay = false;
setseek = -1;
active = false;
+ stream_paused = false;
+ stream_paused_fade = false;
mix_target = MIX_TARGET_STEREO;
AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h
index 21189aea6d..591c00ed18 100644
--- a/scene/audio/audio_player.h
+++ b/scene/audio/audio_player.h
@@ -57,6 +57,8 @@ private:
float pitch_scale;
float volume_db;
bool autoplay;
+ bool stream_paused;
+ bool stream_paused_fade;
StringName bus;
MixTarget mix_target;
@@ -100,6 +102,9 @@ public:
void set_mix_target(MixTarget p_target);
MixTarget get_mix_target() const;
+ void set_stream_paused(bool p_pause);
+ bool get_stream_paused() const;
+
AudioStreamPlayer();
~AudioStreamPlayer();
};
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index acdbd9de08..d17ae1d84c 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -31,7 +31,6 @@
#include "base_button.h"
#include "os/keyboard.h"
-#include "print_string.h"
#include "scene/main/viewport.h"
#include "scene/scene_string_names.h"
@@ -361,7 +360,6 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
return DRAW_DISABLED;
};
- //print_line("press attempt: "+itos(status.press_attempt)+" hover: "+itos(status.hovering)+" pressed: "+itos(status.pressed));
if (status.press_attempt == false && status.hovering && !status.pressed) {
return DRAW_HOVER;
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 03b25a138f..a34f2f1ad5 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "button.h"
-#include "print_string.h"
#include "servers/visual_server.h"
#include "translation.h"
@@ -76,8 +75,6 @@ void Button::_notification(int p_what) {
Color color;
Color color_icon(1, 1, 1, 1);
- //print_line(get_text()+": "+itos(is_flat())+" hover "+itos(get_draw_mode()));
-
Ref<StyleBox> style = get_stylebox("normal");
switch (get_draw_mode()) {
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 34891832e2..8e232c6f46 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -242,6 +242,14 @@ bool ColorPicker::is_raw_mode() const {
return raw_mode_enabled;
}
+void ColorPicker::set_deferred_mode(bool p_enabled) {
+ deferred_mode_enabled = p_enabled;
+}
+
+bool ColorPicker::is_deferred_mode() const {
+ return deferred_mode_enabled;
+}
+
void ColorPicker::_update_text_value() {
bool visible = true;
if (text_is_constructor) {
@@ -328,7 +336,11 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
last_hsv = color;
set_pick_color(color);
_update_color();
+ if (!deferred_mode_enabled)
+ emit_signal("color_changed", color);
+ } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
emit_signal("color_changed", color);
+ changing_color = false;
} else {
changing_color = false;
}
@@ -347,7 +359,8 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
last_hsv = color;
set_pick_color(color);
_update_color();
- emit_signal("color_changed", color);
+ if (!deferred_mode_enabled)
+ emit_signal("color_changed", color);
}
}
@@ -368,7 +381,10 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
last_hsv = color;
set_pick_color(color);
_update_color();
- emit_signal("color_changed", color);
+ if (!deferred_mode_enabled)
+ emit_signal("color_changed", color);
+ else if (!bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT)
+ emit_signal("color_changed", color);
}
Ref<InputEventMouseMotion> mev = p_event;
@@ -383,7 +399,8 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
last_hsv = color;
set_pick_color(color);
_update_color();
- emit_signal("color_changed", color);
+ if (!deferred_mode_enabled)
+ emit_signal("color_changed", color);
}
}
@@ -500,6 +517,8 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPicker::get_pick_color);
ClassDB::bind_method(D_METHOD("set_raw_mode", "mode"), &ColorPicker::set_raw_mode);
ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode);
+ ClassDB::bind_method(D_METHOD("set_deferred_mode", "mode"), &ColorPicker::set_deferred_mode);
+ ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode);
ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha);
ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha);
ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
@@ -522,6 +541,7 @@ void ColorPicker::_bind_methods() {
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_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
}
@@ -533,6 +553,7 @@ ColorPicker::ColorPicker() :
edit_alpha = true;
text_is_constructor = false;
raw_mode_enabled = false;
+ deferred_mode_enabled = false;
changing_color = false;
screen = NULL;
@@ -722,8 +743,9 @@ ColorPicker *ColorPickerButton::get_picker() {
return picker;
}
-PopupPanel *ColorPickerButton::get_popup() const {
+PopupPanel *ColorPickerButton::get_popup() {
+ _update_picker();
return popup;
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 6b63e5fe60..0166da7118 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -67,6 +67,7 @@ private:
Color color;
bool raw_mode_enabled;
+ bool deferred_mode_enabled;
bool updating;
bool changing_color;
float h, s, v;
@@ -107,6 +108,9 @@ public:
void set_raw_mode(bool p_enabled);
bool is_raw_mode() const;
+ void set_deferred_mode(bool p_enabled);
+ bool is_deferred_mode() const;
+
void set_focus_on_line_edit();
ColorPicker();
@@ -140,7 +144,7 @@ public:
bool is_editing_alpha() const;
ColorPicker *get_picker();
- PopupPanel *get_popup() const;
+ PopupPanel *get_popup();
ColorPickerButton();
};
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index a738687a70..fad91c29cf 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -160,9 +160,16 @@ 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);
+
+ bool size_changed = false;
+ if (data.minimum_size_cache != minsize)
+ size_changed = true;
+
data.minimum_size_cache = minsize;
data.minimum_size_valid = true;
- minimum_size_changed();
+
+ if (size_changed)
+ minimum_size_changed();
}
Size2 Control::get_combined_minimum_size() const {
@@ -350,7 +357,7 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
if (data.shader_override.has(E->get()))
hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
- p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_shaders/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph", hint));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_shaders/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Shader,VisualShader", hint));
}
}
{
@@ -656,6 +663,9 @@ void Control::_notification(int p_notification) {
bool Control::clips_input() const {
+ if (get_script_instance()) {
+ return get_script_instance()->call(SceneStringNames::get_singleton()->_clips_input);
+ }
return false;
}
bool Control::has_point(const Point2 &p_point) const {
@@ -759,6 +769,7 @@ void Control::force_drag(const Variant &p_data, Control *p_control) {
void Control::set_drag_preview(Control *p_control) {
ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND(get_viewport()->gui_is_dragging());
get_viewport()->_gui_set_drag_preview(this, p_control);
}
@@ -1267,35 +1278,34 @@ bool Control::has_constant(const StringName &p_name, const StringName &p_type) c
return Theme::get_default()->has_constant(p_name, type);
}
-Size2 Control::get_parent_area_size() const {
-
- ERR_FAIL_COND_V(!is_inside_tree(), Size2());
-
- Size2 parent_size;
+Rect2 Control::get_parent_anchorable_rect() const {
+ if (!is_inside_tree())
+ return Rect2();
+ Rect2 parent_rect;
if (data.parent_canvas_item) {
-
- parent_size = data.parent_canvas_item->_edit_get_rect().size;
+ parent_rect = data.parent_canvas_item->get_anchorable_rect();
} else {
-
- parent_size = get_viewport()->get_visible_rect().size;
+ parent_rect = get_viewport()->get_visible_rect();
}
- return parent_size;
+ return parent_rect;
}
-void Control::_size_changed() {
+Size2 Control::get_parent_area_size() const {
- if (!is_inside_tree())
- return;
+ return get_parent_anchorable_rect().size;
+}
- Size2 parent_size = get_parent_area_size();
+void Control::_size_changed() {
+
+ Rect2 parent_rect = get_parent_anchorable_rect();
float margin_pos[4];
for (int i = 0; i < 4; i++) {
- float area = parent_size[i & 1];
+ float area = parent_rect.size[i & 1];
margin_pos[i] = data.margin[i] + (data.anchor[i] * area);
}
@@ -1325,9 +1335,9 @@ void Control::_size_changed() {
}
// 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();
+ if (is_inside_tree() && Math::abs(Math::sin(data.rotation * 4.0f)) < 0.00001f && get_viewport()->is_snap_controls_to_pixels_enabled()) {
+ new_size_cache = new_size_cache.round();
+ new_pos_cache = new_pos_cache.round();
}
bool pos_changed = new_pos_cache != data.pos_cache;
bool size_changed = new_size_cache != data.size_cache;
@@ -1335,57 +1345,25 @@ void Control::_size_changed() {
data.pos_cache = new_pos_cache;
data.size_cache = new_size_cache;
- if (size_changed) {
- notification(NOTIFICATION_RESIZED);
- }
- if (pos_changed || size_changed) {
- item_rect_changed(size_changed);
- _change_notify_margins();
- _notify_transform();
- }
-
- if (pos_changed && !size_changed) {
- _update_canvas_item_transform(); //move because it won't be updated
- }
-}
-
-float Control::_get_parent_range(int p_idx) const {
-
- if (!is_inside_tree()) {
-
- return 0;
- }
- if (data.parent_canvas_item) {
+ if (is_inside_tree()) {
+ if (size_changed) {
+ notification(NOTIFICATION_RESIZED);
+ }
+ if (pos_changed || size_changed) {
+ item_rect_changed(size_changed);
+ _change_notify_margins();
+ _notify_transform();
+ }
- return data.parent_canvas_item->_edit_get_rect().size[p_idx & 1];
- } else {
- return get_viewport()->get_visible_rect().size[p_idx & 1];
+ if (pos_changed && !size_changed) {
+ _update_canvas_item_transform(); //move because it won't be updated
+ }
}
-
- return 0;
-}
-
-float Control::_get_range(int p_idx) const {
-
- p_idx &= 1;
-
- float parent_range = _get_parent_range(p_idx);
- float from = _a2s(data.margin[p_idx], data.anchor[p_idx], parent_range);
- float to = _a2s(data.margin[p_idx + 2], data.anchor[p_idx + 2], parent_range);
-
- return to - from;
-}
-
-float Control::_s2a(float p_val, float p_anchor, float p_range) const {
- return p_val - (p_anchor * p_range);
-}
-
-float Control::_a2s(float p_val, float p_anchor, float p_range) const {
- return Math::floor(p_val + (p_anchor * p_range));
}
void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) {
- float parent_range = _get_parent_range((p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? 0 : 1);
+ Rect2 parent_rect = get_parent_anchorable_rect();
+ float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
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;
@@ -1401,9 +1379,9 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo
}
if (!p_keep_margin) {
- data.margin[p_margin] = _s2a(previous_margin_pos, data.anchor[p_margin], parent_range);
+ data.margin[p_margin] = 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);
+ data.margin[(p_margin + 2) % 4] = previous_opposite_margin_pos - data.anchor[(p_margin + 2) % 4] * parent_range;
}
}
if (is_inside_tree()) {
@@ -1411,7 +1389,7 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo
}
update();
- _change_notify();
+ _change_notify("anchor");
}
void Control::_set_anchor(Margin p_margin, float p_anchor) {
@@ -1557,8 +1535,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
new_size.y = min_size.y;
}
- float pw = _get_parent_range(0);
- float ph = _get_parent_range(1);
+ Rect2 parent_rect = get_parent_anchorable_rect();
//Left
switch (p_preset) {
@@ -1570,21 +1547,21 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
case PRESET_LEFT_WIDE:
case PRESET_HCENTER_WIDE:
case PRESET_WIDE:
- data.margin[0] = pw * (0.0 - data.anchor[0]) + p_margin;
+ data.margin[0] = parent_rect.size.x * (0.0 - data.anchor[0]) + p_margin + parent_rect.position.x;
break;
case PRESET_CENTER_TOP:
case PRESET_CENTER_BOTTOM:
case PRESET_CENTER:
case PRESET_VCENTER_WIDE:
- data.margin[0] = pw * (0.5 - data.anchor[0]) - new_size.x / 2;
+ data.margin[0] = parent_rect.size.x * (0.5 - data.anchor[0]) - new_size.x / 2 + parent_rect.position.x;
break;
case PRESET_TOP_RIGHT:
case PRESET_BOTTOM_RIGHT:
case PRESET_CENTER_RIGHT:
case PRESET_RIGHT_WIDE:
- data.margin[0] = pw * (1.0 - data.anchor[0]) - new_size.x - p_margin;
+ data.margin[0] = parent_rect.size.x * (1.0 - data.anchor[0]) - new_size.x - p_margin + parent_rect.position.x;
break;
}
@@ -1598,21 +1575,21 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
case PRESET_TOP_WIDE:
case PRESET_VCENTER_WIDE:
case PRESET_WIDE:
- data.margin[1] = ph * (0.0 - data.anchor[1]) + p_margin;
+ data.margin[1] = parent_rect.size.y * (0.0 - data.anchor[1]) + p_margin + parent_rect.position.y;
break;
case PRESET_CENTER_LEFT:
case PRESET_CENTER_RIGHT:
case PRESET_CENTER:
case PRESET_HCENTER_WIDE:
- data.margin[1] = ph * (0.5 - data.anchor[1]) - new_size.y / 2;
+ data.margin[1] = parent_rect.size.y * (0.5 - data.anchor[1]) - new_size.y / 2 + parent_rect.position.y;
break;
case PRESET_BOTTOM_LEFT:
case PRESET_BOTTOM_RIGHT:
case PRESET_CENTER_BOTTOM:
case PRESET_BOTTOM_WIDE:
- data.margin[1] = ph * (1.0 - data.anchor[1]) - new_size.y - p_margin;
+ data.margin[1] = parent_rect.size.y * (1.0 - data.anchor[1]) - new_size.y - p_margin + parent_rect.position.y;
break;
}
@@ -1622,14 +1599,14 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
case PRESET_BOTTOM_LEFT:
case PRESET_CENTER_LEFT:
case PRESET_LEFT_WIDE:
- data.margin[2] = pw * (0.0 - data.anchor[2]) + new_size.x + p_margin;
+ data.margin[2] = parent_rect.size.x * (0.0 - data.anchor[2]) + new_size.x + p_margin + parent_rect.position.x;
break;
case PRESET_CENTER_TOP:
case PRESET_CENTER_BOTTOM:
case PRESET_CENTER:
case PRESET_VCENTER_WIDE:
- data.margin[2] = pw * (0.5 - data.anchor[2]) + new_size.x / 2;
+ data.margin[2] = parent_rect.size.x * (0.5 - data.anchor[2]) + new_size.x / 2 + parent_rect.position.x;
break;
case PRESET_TOP_RIGHT:
@@ -1640,7 +1617,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
case PRESET_BOTTOM_WIDE:
case PRESET_HCENTER_WIDE:
case PRESET_WIDE:
- data.margin[2] = pw * (1.0 - data.anchor[2]) - p_margin;
+ data.margin[2] = parent_rect.size.x * (1.0 - data.anchor[2]) - p_margin + parent_rect.position.x;
break;
}
@@ -1650,14 +1627,14 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
case PRESET_TOP_RIGHT:
case PRESET_CENTER_TOP:
case PRESET_TOP_WIDE:
- data.margin[3] = ph * (0.0 - data.anchor[3]) + new_size.y + p_margin;
+ data.margin[3] = parent_rect.size.y * (0.0 - data.anchor[3]) + new_size.y + p_margin + parent_rect.position.y;
break;
case PRESET_CENTER_LEFT:
case PRESET_CENTER_RIGHT:
case PRESET_CENTER:
case PRESET_HCENTER_WIDE:
- data.margin[3] = ph * (0.5 - data.anchor[3]) + new_size.y / 2;
+ data.margin[3] = parent_rect.size.y * (0.5 - data.anchor[3]) + new_size.y / 2 + parent_rect.position.y;
break;
case PRESET_BOTTOM_LEFT:
@@ -1668,7 +1645,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
case PRESET_BOTTOM_WIDE:
case PRESET_VCENTER_WIDE:
case PRESET_WIDE:
- data.margin[3] = ph * (1.0 - data.anchor[3]) - p_margin;
+ data.margin[3] = parent_rect.size.y * (1.0 - data.anchor[3]) - p_margin + parent_rect.position.y;
break;
}
@@ -1747,31 +1724,29 @@ void Control::set_global_position(const Point2 &p_point) {
set_position(inv.xform(p_point));
}
-void Control::set_position(const Size2 &p_point) {
-
- float pw = _get_parent_range(0);
- float ph = _get_parent_range(1);
+Rect2 Control::_compute_child_rect(const float p_anchors[4], const float p_margins[4]) const {
- float x = _a2s(data.margin[0], data.anchor[0], pw);
- float y = _a2s(data.margin[1], data.anchor[1], ph);
- float x2 = _a2s(data.margin[2], data.anchor[2], pw);
- float y2 = _a2s(data.margin[3], data.anchor[3], ph);
+ Rect2 anchorable = get_parent_anchorable_rect();
+ Rect2 result = anchorable;
+ for (int i = 0; i < 4; i++) {
+ result.grow_margin((Margin)i, p_anchors[i] * anchorable.get_size()[i % 2] + p_margins[i]);
+ }
- Size2 ret = Size2(x2 - x, y2 - y);
- Size2 min = get_combined_minimum_size();
+ return result;
+}
- Size2 size = Size2(MAX(min.width, ret.width), MAX(min.height, ret.height));
- float w = size.x;
- float h = size.y;
+void Control::_compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]) {
- x = p_point.x;
- y = p_point.y;
+ Size2 parent_rect_size = get_parent_anchorable_rect().size;
+ r_margins[0] = Math::floor(p_rect.position.x - (p_anchors[0] * parent_rect_size.x));
+ r_margins[1] = Math::floor(p_rect.position.y - (p_anchors[1] * parent_rect_size.y));
+ r_margins[2] = Math::floor(p_rect.position.x + p_rect.size.x - (p_anchors[2] * parent_rect_size.x));
+ r_margins[3] = Math::floor(p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y));
+}
- data.margin[0] = _s2a(x, data.anchor[0], pw);
- data.margin[1] = _s2a(y, data.anchor[1], ph);
- data.margin[2] = _s2a(x + w, data.anchor[2], pw);
- data.margin[3] = _s2a(y + h, data.anchor[3], ph);
+void Control::set_position(const Size2 &p_point) {
+ _compute_margins(Rect2(p_point, data.size_cache), data.anchor, data.margin);
_size_changed();
}
@@ -1784,18 +1759,7 @@ void Control::set_size(const Size2 &p_size) {
if (new_size.y < min.y)
new_size.y = min.y;
- float pw = _get_parent_range(0);
- float ph = _get_parent_range(1);
-
- float x = _a2s(data.margin[0], data.anchor[0], pw);
- float y = _a2s(data.margin[1], data.anchor[1], ph);
-
- float w = new_size.width;
- float h = new_size.height;
-
- data.margin[2] = _s2a(x + w, data.anchor[2], pw);
- data.margin[3] = _s2a(y + h, data.anchor[3], ph);
-
+ _compute_margins(Rect2(data.pos_cache, new_size), data.anchor, data.margin);
_size_changed();
}
@@ -1826,6 +1790,11 @@ Rect2 Control::get_rect() const {
return Rect2(get_position(), get_size());
}
+Rect2 Control::get_anchorable_rect() const {
+
+ return Rect2(Point2(), get_size());
+}
+
void Control::add_icon_override(const StringName &p_name, const Ref<Texture> &p_icon) {
ERR_FAIL_COND(p_icon.is_null());
@@ -2223,10 +2192,17 @@ void Control::set_tooltip(const String &p_tooltip) {
data.tooltip = p_tooltip;
}
+
String Control::get_tooltip(const Point2 &p_pos) const {
return data.tooltip;
}
+Control *Control::make_custom_tooltip(const String &p_text) const {
+ if (get_script_instance()) {
+ return const_cast<Control *>(this)->call("_make_custom_tooltip", p_text);
+ }
+ return NULL;
+}
void Control::set_default_cursor_shape(CursorShape p_shape) {
@@ -2325,12 +2301,11 @@ Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
Point2 points[4];
Transform2D xform = get_global_transform();
- Rect2 rect = _edit_get_rect();
- points[0] = xform.xform(rect.position);
- points[1] = xform.xform(rect.position + Point2(rect.size.x, 0));
- points[2] = xform.xform(rect.position + rect.size);
- points[3] = xform.xform(rect.position + Point2(0, rect.size.y));
+ points[0] = xform.xform(Point2());
+ points[1] = xform.xform(Point2(get_size().x, 0));
+ points[2] = xform.xform(get_size());
+ points[3] = xform.xform(Point2(0, get_size().y));
const Vector2 dir[4] = {
Vector2(-1, 0),
@@ -2384,12 +2359,11 @@ void Control::_window_find_focus_neighbour(const Vector2 &p_dir, Node *p_at, con
Point2 points[4];
Transform2D xform = c->get_global_transform();
- Rect2 rect = c->_edit_get_rect();
- points[0] = xform.xform(rect.position);
- points[1] = xform.xform(rect.position + Point2(rect.size.x, 0));
- points[2] = xform.xform(rect.position + rect.size);
- points[3] = xform.xform(rect.position + Point2(0, rect.size.y));
+ points[0] = xform.xform(Point2());
+ points[1] = xform.xform(Point2(get_size().x, 0));
+ points[2] = xform.xform(get_size());
+ points[3] = xform.xform(Point2(0, get_size().y));
float min = 1e7;
@@ -2857,6 +2831,8 @@ void Control::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_drag_data", PropertyInfo(Variant::VECTOR2, "position")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
+ BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input"));
ADD_GROUP("Anchor", "anchor_");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_LEFT);
@@ -2888,12 +2864,12 @@ void Control::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
ADD_GROUP("Focus", "focus_");
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT);
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
- ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
- 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_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_LEFT);
+ ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_TOP);
+ ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_RIGHT);
+ ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
+ ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "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_");
@@ -2980,7 +2956,7 @@ void Control::_bind_methods() {
BIND_ENUM_CONSTANT(ANCHOR_END);
ADD_SIGNAL(MethodInfo("resized"));
- ADD_SIGNAL(MethodInfo("gui_input", PropertyInfo(Variant::OBJECT, "ev", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
+ ADD_SIGNAL(MethodInfo("gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
ADD_SIGNAL(MethodInfo("focus_entered"));
@@ -3001,7 +2977,6 @@ Control::Control() {
data.SI = NULL;
data.MI = NULL;
data.RI = NULL;
- data.modal = false;
data.theme_owner = NULL;
data.modal_exclusive = false;
data.default_cursor = CURSOR_ARROW;
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 9124256624..c6bd2f097d 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -31,13 +31,13 @@
#ifndef CONTROL_H
#define CONTROL_H
-#include "math_2d.h"
#include "rid.h"
#include "scene/2d/canvas_item.h"
#include "scene/gui/shortcut.h"
#include "scene/main/node.h"
#include "scene/main/timer.h"
#include "scene/resources/theme.h"
+#include "transform_2d.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -182,7 +182,6 @@ private:
Control *parent;
ObjectID drag_owner;
- bool modal;
bool modal_exclusive;
uint64_t modal_frame; //frame used to put something as modal
Ref<Theme> theme;
@@ -202,12 +201,12 @@ private:
NodePath focus_next;
NodePath focus_prev;
- HashMap<StringName, Ref<Texture>, StringNameHasher> icon_override;
- HashMap<StringName, Ref<Shader>, StringNameHasher> shader_override;
- HashMap<StringName, Ref<StyleBox>, StringNameHasher> style_override;
- HashMap<StringName, Ref<Font>, StringNameHasher> font_override;
- HashMap<StringName, Color, StringNameHasher> color_override;
- HashMap<StringName, int, StringNameHasher> constant_override;
+ HashMap<StringName, Ref<Texture> > icon_override;
+ HashMap<StringName, Ref<Shader> > shader_override;
+ HashMap<StringName, Ref<StyleBox> > style_override;
+ HashMap<StringName, Ref<Font> > font_override;
+ HashMap<StringName, Color> color_override;
+ HashMap<StringName, int> constant_override;
Map<Ref<Font>, int> font_refcount;
} data;
@@ -220,10 +219,6 @@ private:
void _set_anchor(Margin p_margin, float p_anchor);
- float _get_parent_range(int p_idx) const;
- float _get_range(int p_idx) const;
- float _s2a(float p_val, float p_anchor, float p_range) const;
- float _a2s(float p_val, float p_anchor, float p_range) const;
void _propagate_theme_changed(CanvasItem *p_at, Control *p_owner, bool p_assign = true);
void _theme_changed();
@@ -233,6 +228,9 @@ private:
void _update_scroll();
void _resize(const Size2 &p_size);
+ Rect2 _compute_child_rect(const float p_anchors[4], const float p_margins[4]) const;
+ void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]);
+
void _size_changed();
String _get_tooltip() const;
@@ -283,6 +281,7 @@ public:
};
+ /* EDITOR */
virtual Dictionary _edit_get_state() const;
virtual void _edit_set_state(const Dictionary &p_state);
@@ -358,6 +357,7 @@ public:
Rect2 get_rect() const;
Rect2 get_global_rect() const;
Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server
+ Rect2 get_anchorable_rect() const;
void set_rotation(float p_radians);
void set_rotation_degrees(float p_degrees);
@@ -453,6 +453,7 @@ public:
void set_tooltip(const String &p_tooltip);
virtual String get_tooltip(const Point2 &p_pos) const;
+ virtual Control *make_custom_tooltip(const String &p_text) const;
/* CURSOR */
@@ -465,6 +466,7 @@ public:
bool is_toplevel_control() const;
Size2 get_parent_area_size() const;
+ Rect2 get_parent_anchorable_rect() const;
void grab_click_focus();
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 25cb74a494..9bddaa7d29 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -284,7 +284,13 @@ bool FileDialog::_is_open_should_be_disabled() {
if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE)
return false;
- TreeItem *ti = tree->get_selected();
+ TreeItem *ti = tree->get_next_selected(tree->get_root());
+ while (ti) {
+ TreeItem *prev_ti = ti;
+ ti = tree->get_next_selected(tree->get_root());
+ if (ti == prev_ti)
+ break;
+ }
// We have something that we can't select?
if (!ti)
return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder.
@@ -328,6 +334,10 @@ void FileDialog::deselect_items() {
}
}
+void FileDialog::_tree_multi_selected(Object *p_object, int p_cell, bool p_selected) {
+ _tree_selected();
+}
+
void FileDialog::_tree_selected() {
TreeItem *ti = tree->get_selected();
@@ -582,7 +592,8 @@ void FileDialog::set_current_file(const String &p_file) {
int lp = p_file.find_last(".");
if (lp != -1) {
file->select(0, lp);
- file->grab_focus();
+ if (file->is_inside_tree())
+ file->grab_focus();
}
}
void FileDialog::set_current_path(const String &p_path) {
@@ -753,6 +764,7 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_input"), &FileDialog::_unhandled_input);
+ ClassDB::bind_method(D_METHOD("_tree_multi_selected"), &FileDialog::_tree_multi_selected);
ClassDB::bind_method(D_METHOD("_tree_selected"), &FileDialog::_tree_selected);
ClassDB::bind_method(D_METHOD("_tree_item_activated"), &FileDialog::_tree_item_activated);
ClassDB::bind_method(D_METHOD("_dir_entered"), &FileDialog::_dir_entered);
@@ -793,7 +805,7 @@ 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, "mode", PROPERTY_HINT_ENUM, "Open File,Open Files,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");
@@ -889,6 +901,7 @@ FileDialog::FileDialog() {
_update_drives();
connect("confirmed", this, "_action_pressed");
+ tree->connect("multi_selected", this, "_tree_multi_selected", varray(), CONNECT_DEFERRED);
tree->connect("cell_selected", this, "_tree_selected", varray(), CONNECT_DEFERRED);
tree->connect("item_activated", this, "_tree_item_activated", varray());
tree->connect("nothing_selected", this, "deselect_items");
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index ad483d5dab..3227f1c3a8 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -104,6 +104,7 @@ private:
void update_file_list();
void update_filters();
+ void _tree_multi_selected(Object *p_object, int p_cell, bool p_selected);
void _tree_selected();
void _select_drive(int p_idx);
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index b5622604e2..e82c0c4ad1 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -147,7 +147,6 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
grabbed = _get_point_from_pos(x);
//grab or select
if (grabbed != -1) {
- grabbed = false;
return;
}
@@ -256,7 +255,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
if (!valid)
return;
- points[grabbed].offset = newofs;
+ points.write[grabbed].offset = newofs;
points.sort();
for (int i = 0; i < points.size(); i++) {
@@ -407,7 +406,7 @@ void GradientEdit::_color_changed(const Color &p_color) {
if (grabbed == -1)
return;
- points[grabbed].color = p_color;
+ points.write[grabbed].color = p_color;
update();
emit_signal("ramp_changed");
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index e2c730a56e..8797ab6fd3 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -268,6 +268,10 @@ void GraphEdit::remove_child_notify(Node *p_child) {
void GraphEdit::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal");
+ port_grab_distance_vertical = get_constant("port_grab_distance_vertical");
+ }
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
@@ -343,8 +347,6 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
Ref<Texture> port = get_icon("port", "GraphNode");
- float grab_r_extend = 2.0;
- float grab_r = port->get_width() * 0.5 * grab_r_extend;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -354,14 +356,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (pos.distance_to(p_point) < grab_r)
+ if (is_in_hot_zone(pos, p_point))
return true;
}
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (pos.distance_to(p_point) < grab_r) {
+ if (is_in_hot_zone(pos, p_point)) {
return true;
}
}
@@ -372,13 +374,11 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
- float grab_r_extend = 2.0;
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos(mb->get_position().x, mb->get_position().y);
- float grab_r = port->get_width() * 0.5 * grab_r_extend;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -388,7 +388,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (pos.distance_to(mpos) < grab_r) {
+ if (is_in_hot_zone(pos, mpos)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
@@ -435,8 +435,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
-
- if (pos.distance_to(mpos) < grab_r) {
+ if (is_in_hot_zone(pos, mpos)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
@@ -492,7 +491,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos = mm->get_position();
- float grab_r = port->get_width() * 0.5 * grab_r_extend;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -504,7 +502,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
int type = gn->get_connection_output_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && pos.distance_to(mpos) < grab_r) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
@@ -519,7 +517,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && pos.distance_to(mpos) < grab_r) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -559,6 +557,57 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
+bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) {
+
+ if (p_control->is_set_as_toplevel() || !p_control->is_visible())
+ return false;
+
+ if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
+ //test children
+ for (int i = 0; i < p_control->get_child_count(); i++) {
+ Control *subchild = Object::cast_to<Control>(p_control->get_child(i));
+ if (!subchild)
+ continue;
+ if (_check_clickable_control(subchild, pos - subchild->get_position())) {
+ return true;
+ }
+ }
+
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) {
+ if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos))
+ return false;
+
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *child = Object::cast_to<Control>(get_child(i));
+ if (!child)
+ continue;
+ Rect2 rect = child->get_rect();
+ if (rect.has_point(p_mouse_pos)) {
+
+ //check sub-controls
+ Vector2 subpos = p_mouse_pos - rect.position;
+
+ for (int j = 0; j < child->get_child_count(); j++) {
+ Control *subchild = Object::cast_to<Control>(child->get_child(j));
+ if (!subchild)
+ continue;
+
+ if (_check_clickable_control(subchild, subpos - subchild->get_position())) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
template <class Vector2>
static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) {
/* Formula from Wikipedia article on Bezier curves. */
@@ -1230,7 +1279,7 @@ void GraphEdit::_bind_methods() {
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")));
ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
- ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node")));
+ ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("delete_nodes_request"));
ADD_SIGNAL(MethodInfo("_begin_node_move"));
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 14789001e4..31a449eb59 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -81,6 +81,9 @@ private:
HScrollBar *h_scroll;
VScrollBar *v_scroll;
+ float port_grab_distance_horizontal;
+ float port_grab_distance_vertical;
+
bool connecting;
String connecting_from;
bool connecting_out;
@@ -127,6 +130,9 @@ private:
Control *connections_layer;
GraphEditFilter *top_layer;
void _top_layer_input(const Ref<InputEvent> &p_ev);
+
+ bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos);
+
void _top_layer_draw();
void _connections_layer_draw();
void _update_scroll_offset();
@@ -166,6 +172,8 @@ private:
void _snap_toggled();
void _snap_value_changed(double);
+ bool _check_clickable_control(Control *p_control, const Vector2 &pos);
+
protected:
static void _bind_methods();
virtual void add_child_notify(Node *p_child);
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 57b9a9a11b..9f5c12e87f 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -72,7 +72,7 @@ void ItemList::set_item_text(int p_idx, const String &p_text) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].text = p_text;
+ items.write[p_idx].text = p_text;
update();
shape_changed = true;
}
@@ -85,7 +85,7 @@ String ItemList::get_item_text(int p_idx) const {
void ItemList::set_item_tooltip_enabled(int p_idx, const bool p_enabled) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].tooltip_enabled = p_enabled;
+ items.write[p_idx].tooltip_enabled = p_enabled;
}
bool ItemList::is_item_tooltip_enabled(int p_idx) const {
@@ -97,7 +97,7 @@ void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].tooltip = p_tooltip;
+ items.write[p_idx].tooltip = p_tooltip;
update();
shape_changed = true;
}
@@ -112,7 +112,7 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].icon = p_icon;
+ items.write[p_idx].icon = p_icon;
update();
shape_changed = true;
}
@@ -128,7 +128,7 @@ void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].icon_region = p_region;
+ items.write[p_idx].icon_region = p_region;
update();
shape_changed = true;
}
@@ -144,7 +144,7 @@ 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;
+ items.write[p_idx].icon_modulate = p_modulate;
update();
}
@@ -159,7 +159,7 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].custom_bg = p_custom_bg_color;
+ items.write[p_idx].custom_bg = p_custom_bg_color;
}
Color ItemList::get_item_custom_bg_color(int p_idx) const {
@@ -173,7 +173,7 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].custom_fg = p_custom_fg_color;
+ items.write[p_idx].custom_fg = p_custom_fg_color;
}
Color ItemList::get_item_custom_fg_color(int p_idx) const {
@@ -187,7 +187,7 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture> &p_tag_icon) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].tag_icon = p_tag_icon;
+ items.write[p_idx].tag_icon = p_tag_icon;
update();
shape_changed = true;
}
@@ -202,7 +202,7 @@ void ItemList::set_item_selectable(int p_idx, bool p_selectable) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].selectable = p_selectable;
+ items.write[p_idx].selectable = p_selectable;
}
bool ItemList::is_item_selectable(int p_idx) const {
@@ -215,7 +215,7 @@ void ItemList::set_item_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].disabled = p_disabled;
+ items.write[p_idx].disabled = p_disabled;
update();
}
@@ -229,7 +229,7 @@ void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].metadata = p_metadata;
+ items.write[p_idx].metadata = p_metadata;
update();
shape_changed = true;
}
@@ -250,7 +250,7 @@ void ItemList::select(int p_idx, bool p_single) {
}
for (int i = 0; i < items.size(); i++) {
- items[i].selected = p_idx == i;
+ items.write[i].selected = p_idx == i;
}
current = p_idx;
@@ -258,7 +258,7 @@ void ItemList::select(int p_idx, bool p_single) {
} else {
if (items[p_idx].selectable && !items[p_idx].disabled) {
- items[p_idx].selected = true;
+ items.write[p_idx].selected = true;
}
}
update();
@@ -268,10 +268,10 @@ void ItemList::unselect(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
if (select_mode != SELECT_MULTI) {
- items[p_idx].selected = false;
+ items.write[p_idx].selected = false;
current = -1;
} else {
- items[p_idx].selected = false;
+ items.write[p_idx].selected = false;
}
update();
}
@@ -283,9 +283,9 @@ void ItemList::unselect_all() {
for (int i = 0; i < items.size(); i++) {
- items[i].selected = false;
+ items.write[i].selected = false;
}
-
+ current = -1;
update();
}
@@ -502,7 +502,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
bool selected = !items[j].selected;
select(j, false);
if (selected)
- emit_signal("multi_selected", i, true);
+ emit_signal("multi_selected", j, true);
}
if (mb->get_button_index() == BUTTON_RIGHT) {
@@ -869,8 +869,8 @@ void ItemList::_notification(int p_what) {
// elements need to adapt to the selected size
minsize.y += vseparation;
minsize.x += hseparation;
- items[i].rect_cache.size = minsize;
- items[i].min_rect_cache.size = minsize;
+ items.write[i].rect_cache.size = minsize;
+ items.write[i].min_rect_cache.size = minsize;
}
int fit_size = size.x - bg->get_minimum_size().width - mw;
@@ -897,8 +897,8 @@ void ItemList::_notification(int p_what) {
}
if (same_column_width)
- items[i].rect_cache.size.x = max_column_width;
- items[i].rect_cache.position = ofs;
+ items.write[i].rect_cache.size.x = max_column_width;
+ items.write[i].rect_cache.position = ofs;
max_h = MAX(max_h, items[i].rect_cache.size.y);
ofs.x += items[i].rect_cache.size.x + hseparation;
col++;
@@ -908,7 +908,7 @@ void ItemList::_notification(int p_what) {
separators.push_back(ofs.y + max_h + vseparation / 2);
for (int j = i; j >= 0 && col > 0; j--, col--) {
- items[j].rect_cache.size.y = max_h;
+ items.write[j].rect_cache.size.y = max_h;
}
ofs.x = 0;
@@ -919,7 +919,7 @@ void ItemList::_notification(int p_what) {
}
for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) {
- items[j].rect_cache.size.y = max_h;
+ items.write[j].rect_cache.size.y = max_h;
}
if (all_fit) {
@@ -942,6 +942,7 @@ void ItemList::_notification(int p_what) {
}
}
+ minimum_size_changed();
shape_changed = false;
}
@@ -1102,8 +1103,8 @@ void ItemList::_notification(int p_what) {
int cs = j < ss ? font->get_char_size(items[i].text[j], items[i].text[j + 1]).x : 0;
if (ofs + cs > max_len || j == ss) {
- line_limit_cache[line] = j;
- line_size_cache[line] = ofs;
+ line_limit_cache.write[line] = j;
+ line_size_cache.write[line] = ofs;
line++;
ofs = 0;
if (line >= max_text_lines)
@@ -1422,6 +1423,9 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_custom_bg_color", "idx", "custom_bg_color"), &ItemList::set_item_custom_bg_color);
ClassDB::bind_method(D_METHOD("get_item_custom_bg_color", "idx"), &ItemList::get_item_custom_bg_color);
+ ClassDB::bind_method(D_METHOD("set_item_custom_fg_color", "idx", "custom_fg_color"), &ItemList::set_item_custom_fg_color);
+ ClassDB::bind_method(D_METHOD("get_item_custom_fg_color", "idx"), &ItemList::get_item_custom_fg_color);
+
ClassDB::bind_method(D_METHOD("set_item_tooltip_enabled", "idx", "enable"), &ItemList::set_item_tooltip_enabled);
ClassDB::bind_method(D_METHOD("is_item_tooltip_enabled", "idx"), &ItemList::is_item_tooltip_enabled);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 9af479c1cc..0b36e1663c 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -75,7 +75,7 @@ void Label::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
- if (clip || autowrap) {
+ if (clip) {
VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 0cd5219f8f..1f3d5e6e13 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -35,7 +35,9 @@
#include "os/os.h"
#include "print_string.h"
#include "translation.h"
+
#ifdef TOOLS_ENABLED
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#endif
@@ -64,6 +66,12 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
_reset_caret_blink_timer();
if (b->is_pressed()) {
+ if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) {
+ clear_button_status.press_attempt = true;
+ clear_button_status.pressing_inside = true;
+ return;
+ }
+
shift_selection_check_pre(b->get_shift());
set_cursor_at_pixel_pos(b->get_position().x);
@@ -100,6 +108,15 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} else {
+ if (!text.empty() && is_editable() && clear_button_enabled) {
+ bool press_attempt = clear_button_status.press_attempt;
+ clear_button_status.press_attempt = false;
+ if (press_attempt && clear_button_status.pressing_inside && _is_over_clear_button(b->get_position())) {
+ clear();
+ return;
+ }
+ }
+
if ((!selection.creating) && (!selection.doubleclick)) {
deselect();
}
@@ -117,6 +134,14 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (m.is_valid()) {
+ if (!text.empty() && is_editable() && clear_button_enabled) {
+ bool last_press_inside = clear_button_status.pressing_inside;
+ clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position());
+ if (last_press_inside != clear_button_status.pressing_inside) {
+ update();
+ }
+ }
+
if (m->get_button_mask() & BUTTON_LEFT) {
if (selection.creating) {
@@ -548,6 +573,25 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
}
}
+Control::CursorShape LineEdit::get_cursor_shape(const Point2 &p_pos) const {
+ if (!text.empty() && is_editable() && _is_over_clear_button(p_pos)) {
+ return CURSOR_ARROW;
+ }
+ return Control::get_cursor_shape(p_pos);
+}
+
+bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const {
+ if (!clear_button_enabled || !has_point(p_pos)) {
+ return false;
+ }
+ Ref<Texture> icon = Control::get_icon("clear");
+ int x_ofs = get_stylebox("normal")->get_offset().x;
+ if (p_pos.x > get_size().width - icon->get_width() - x_ofs) {
+ return true;
+ }
+ return false;
+}
+
void LineEdit::_notification(int p_what) {
switch (p_what) {
@@ -640,7 +684,7 @@ void LineEdit::_notification(int p_what) {
int char_ofs = window_pos;
int y_area = height - style->get_minimum_size().height;
- int y_ofs = style->get_offset().y;
+ int y_ofs = style->get_offset().y + (y_area - font->get_height()) / 2;
int font_ascent = font->get_ascent();
@@ -655,10 +699,26 @@ void LineEdit::_notification(int p_what) {
font_color.a *= placeholder_alpha;
font_color.a *= disabled_alpha;
- if (has_icon("right_icon")) {
- Ref<Texture> r_icon = Control::get_icon("right_icon");
- ofs_max -= r_icon->get_width();
- r_icon->draw(ci, Point2(width - r_icon->get_width() - x_ofs, height / 2 - r_icon->get_height() / 2), Color(1, 1, 1, disabled_alpha * .9));
+ bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
+ if (right_icon.is_valid() || display_clear_icon) {
+ Ref<Texture> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon;
+ Color color_icon(1, 1, 1, disabled_alpha * .9);
+ if (display_clear_icon) {
+ if (clear_button_status.press_attempt && clear_button_status.pressing_inside) {
+ color_icon = get_color("clear_button_color_pressed");
+ } else {
+ color_icon = get_color("clear_button_color");
+ }
+ }
+ r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon);
+
+ if (align == ALIGN_CENTER) {
+ if (window_pos == 0) {
+ x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2);
+ }
+ } else {
+ x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT));
+ }
}
int caret_height = font->get_height() > y_area ? y_area : font->get_height();
@@ -711,11 +771,16 @@ 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);
- drawer.draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
+ int yofs = y_ofs + (caret_height - font->get_height()) / 2;
+ drawer.draw_char(ci, Point2(x_ofs, yofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
if (char_ofs == cursor_pos && draw_caret) {
if (ime_text.length() == 0) {
+#ifdef TOOLS_ENABLED
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
+#else
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(1, caret_height)), cursor_color);
+#endif
}
}
@@ -754,7 +819,11 @@ void LineEdit::_notification(int p_what) {
if (char_ofs == cursor_pos && draw_caret) { //may be at the end
if (ime_text.length() == 0) {
+#ifdef TOOLS_ENABLED
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
+#else
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(1, caret_height)), cursor_color);
+#endif
}
}
@@ -797,15 +866,14 @@ void LineEdit::_notification(int p_what) {
void LineEdit::copy_text() {
- if (selection.enabled) {
-
+ if (selection.enabled && !pass) {
OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
}
}
void LineEdit::cut_text() {
- if (selection.enabled) {
+ if (selection.enabled && !pass) {
OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
selection_delete();
}
@@ -1085,9 +1153,8 @@ void LineEdit::set_cursor_position(int p_pos) {
} else if (cursor_pos > window_pos) {
/* Adjust window if cursor goes too much to the right */
int window_width = get_size().width - style->get_minimum_size().width;
- if (has_icon("right_icon")) {
- Ref<Texture> r_icon = Control::get_icon("right_icon");
- window_width -= r_icon->get_width();
+ if (right_icon.is_valid()) {
+ window_width -= right_icon->get_width();
}
if (window_width < 0)
@@ -1374,10 +1441,26 @@ void LineEdit::set_expand_to_text_length(bool p_enabled) {
}
bool LineEdit::get_expand_to_text_length() const {
-
return expand_to_text_length;
}
+void LineEdit::set_clear_button_enabled(bool p_enabled) {
+ clear_button_enabled = p_enabled;
+ update();
+}
+
+bool LineEdit::is_clear_button_enabled() const {
+ return clear_button_enabled;
+}
+
+void LineEdit::set_right_icon(const Ref<Texture> &p_icon) {
+ if (right_icon == p_icon) {
+ return;
+ }
+ right_icon = p_icon;
+ update();
+}
+
void LineEdit::_ime_text_callback(void *p_self, String p_text, Point2 p_selection) {
LineEdit *self = (LineEdit *)p_self;
self->ime_text = p_text;
@@ -1470,6 +1553,8 @@ void LineEdit::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("set_clear_button_enabled", "enable"), &LineEdit::set_clear_button_enabled);
+ ClassDB::bind_method(D_METHOD("is_clear_button_enabled"), &LineEdit::is_clear_button_enabled);
ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text")));
@@ -1497,6 +1582,7 @@ void LineEdit::_bind_methods() {
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_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_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");
@@ -1521,6 +1607,7 @@ LineEdit::LineEdit() {
secret_character = "*";
text_changed_dirty = false;
placeholder_alpha = 0.6;
+ clear_button_enabled = false;
deselect();
set_focus_mode(FOCUS_ALL);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index e9314ba8dd..5294d99da0 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -87,6 +87,10 @@ private:
int cached_width;
int cached_placeholder_width;
+ bool clear_button_enabled;
+
+ Ref<Texture> right_icon;
+
struct Selection {
int begin;
@@ -105,6 +109,13 @@ private:
List<TextOperation> undo_stack;
List<TextOperation>::Element *undo_stack_pos;
+ struct ClearButtonStatus {
+ bool press_attempt;
+ bool pressing_inside;
+ } clear_button_status;
+
+ bool _is_over_clear_button(const Point2 &p_pos) const;
+
void _clear_undo_stack();
void _clear_redo();
void _create_undo_state();
@@ -150,6 +161,8 @@ public:
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
virtual void drop_data(const Point2 &p_point, const Variant &p_data);
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const;
+
void menu_option(int p_option);
void set_context_menu_enabled(bool p_enable);
bool is_context_menu_enabled();
@@ -201,6 +214,11 @@ public:
void set_expand_to_text_length(bool p_enabled);
bool get_expand_to_text_length() const;
+ void set_clear_button_enabled(bool p_enabled);
+ bool is_clear_button_enabled() const;
+
+ void set_right_icon(const Ref<Texture> &p_icon);
+
virtual bool is_text_field() const;
LineEdit();
~LineEdit();
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index d862e8669c..8560efdde5 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -68,8 +68,6 @@ void LinkButton::_notification(int p_what) {
Color color;
bool do_underline = false;
- //print_line(get_text()+": "+itos(is_flat())+" hover "+itos(get_draw_mode()));
-
switch (get_draw_mode()) {
case DRAW_NORMAL: {
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 2356444ecb..0636accfee 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -43,7 +43,6 @@ class MenuButton : public Button {
bool clicked;
bool disable_shortcuts;
PopupMenu *popup;
- virtual void pressed();
void _unhandled_key_input(Ref<InputEvent> p_event);
Array _get_items() const;
@@ -55,6 +54,8 @@ protected:
static void _bind_methods();
public:
+ virtual void pressed();
+
PopupMenu *get_popup() const;
void set_disable_shortcuts(bool p_disabled);
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index c5e4149782..2901176a69 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -36,7 +36,7 @@ Size2 OptionButton::get_minimum_size() const {
Size2 minsize = Button::get_minimum_size();
if (has_icon("arrow"))
- minsize.width += Control::get_icon("arrow")->get_width();
+ minsize.width += Control::get_icon("arrow")->get_width() + get_constant("hseparation");
return minsize;
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 18e609c798..436dda41a4 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -398,10 +398,19 @@ void PopupMenu::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(get_parent());
+ if (pm) {
+ // Inherit submenu's popup delay time from parent menu
+ float pm_delay = pm->get_submenu_popup_delay();
+ set_submenu_popup_delay(pm_delay);
+ }
+ } break;
case NOTIFICATION_TRANSLATION_CHANGED: {
for (int i = 0; i < items.size(); i++) {
- items[i].xl_text = tr(items[i].text);
+ items.write[i].xl_text = tr(items[i].text);
}
minimum_size_changed();
@@ -421,6 +430,8 @@ void PopupMenu::_notification(int p_what) {
Ref<Texture> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") };
Ref<Texture> submenu = get_icon("submenu");
Ref<StyleBox> separator = get_stylebox("separator");
+ Ref<StyleBox> labeled_separator_left = get_stylebox("labeled_separator_left");
+ Ref<StyleBox> labeled_separator_right = get_stylebox("labeled_separator_right");
style->draw(ci, Rect2(Point2(), get_size()));
Point2 ofs = style->get_offset();
@@ -457,10 +468,25 @@ void PopupMenu::_notification(int p_what) {
hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
}
+ String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text;
+
if (items[i].separator) {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
- 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 (text != String()) {
+ int ss = font->get_string_size(text).width;
+ int center = (get_size().width) / 2;
+ int l = center - ss / 2;
+ int r = center + ss / 2;
+ if (l > item_ofs.x) {
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
+ }
+ if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
+ labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
+ }
+ } else {
+ 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_type) {
@@ -480,8 +506,13 @@ void PopupMenu::_notification(int p_what) {
}
item_ofs.y += font->get_ascent();
- String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text;
- if (!items[i].separator) {
+ if (items[i].separator) {
+
+ if (text != String()) {
+ int center = (get_size().width - font->get_string_size(text).width) / 2;
+ font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
+ }
+ } else {
font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
}
@@ -493,12 +524,17 @@ void PopupMenu::_notification(int p_what) {
font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, i == mouse_over ? font_color_hover : font_color_accel);
}
- items[i]._ofs_cache = ofs.y;
+ items.write[i]._ofs_cache = ofs.y;
ofs.y += h;
}
} break;
+ case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
+
+ if (hide_on_window_lose_focus)
+ hide();
+ } break;
case NOTIFICATION_MOUSE_ENTER: {
grab_focus();
@@ -591,7 +627,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel
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;
+ items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
update();
minimum_size_changed();
}
@@ -599,7 +635,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p
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;
+ items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
update();
minimum_size_changed();
}
@@ -671,7 +707,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo
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;
+ items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
update();
minimum_size_changed();
}
@@ -693,8 +729,8 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
void PopupMenu::set_item_text(int p_idx, const String &p_text) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].text = p_text;
- items[p_idx].xl_text = tr(p_text);
+ items.write[p_idx].text = p_text;
+ items.write[p_idx].xl_text = tr(p_text);
update();
minimum_size_changed();
@@ -702,7 +738,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].icon = p_icon;
+ items.write[p_idx].icon = p_icon;
update();
minimum_size_changed();
@@ -711,7 +747,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].checked = p_checked;
+ items.write[p_idx].checked = p_checked;
update();
minimum_size_changed();
@@ -719,7 +755,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
void PopupMenu::set_item_id(int p_idx, int p_ID) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].ID = p_ID;
+ items.write[p_idx].ID = p_ID;
update();
minimum_size_changed();
@@ -728,7 +764,7 @@ void PopupMenu::set_item_id(int p_idx, int p_ID) {
void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].accel = p_accel;
+ items.write[p_idx].accel = p_accel;
update();
minimum_size_changed();
@@ -737,7 +773,7 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
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;
+ items.write[p_idx].metadata = p_meta;
update();
minimum_size_changed();
}
@@ -745,7 +781,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].disabled = p_disabled;
+ items.write[p_idx].disabled = p_disabled;
update();
minimum_size_changed();
}
@@ -753,7 +789,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
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;
+ items.write[p_idx].submenu = p_submenu;
update();
minimum_size_changed();
}
@@ -761,7 +797,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].checked = !items[p_idx].checked;
+ items.write[p_idx].checked = !items[p_idx].checked;
update();
minimum_size_changed();
}
@@ -855,7 +891,7 @@ int PopupMenu::get_item_state(int p_idx) const {
void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].separator = p_separator;
+ items.write[p_idx].separator = p_separator;
update();
}
@@ -867,21 +903,21 @@ 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_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
+ items.write[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;
+ items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
update();
}
void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].tooltip = p_tooltip;
+ items.write[p_idx].tooltip = p_tooltip;
update();
}
@@ -890,8 +926,8 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo
if (items[p_idx].shortcut.is_valid()) {
_unref_shortcut(items[p_idx].shortcut);
}
- items[p_idx].shortcut = p_shortcut;
- items[p_idx].shortcut_is_global = p_global;
+ items.write[p_idx].shortcut = p_shortcut;
+ items.write[p_idx].shortcut_is_global = p_global;
if (items[p_idx].shortcut.is_valid()) {
_ref_shortcut(items[p_idx].shortcut);
@@ -903,7 +939,7 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo
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;
+ items.write[p_idx].h_ofs = p_offset;
update();
minimum_size_changed();
}
@@ -911,14 +947,14 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].state = p_state;
+ items.write[p_idx].state = p_state;
update();
}
void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].shortcut_is_disabled = p_disabled;
+ items.write[p_idx].shortcut_is_disabled = p_disabled;
update();
}
@@ -929,9 +965,9 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
return;
}
- ++items[p_idx].state;
- if (items[p_idx].max_states <= items[p_idx].state)
- items[p_idx].state = 0;
+ ++items.write[p_idx].state;
+ if (items.write[p_idx].max_states <= items[p_idx].state)
+ items.write[p_idx].state = 0;
update();
}
@@ -1013,10 +1049,8 @@ void PopupMenu::activate_item(int p_item) {
ERR_FAIL_INDEX(p_item, items.size());
ERR_FAIL_COND(items[p_item].separator);
int id = items[p_item].ID >= 0 ? items[p_item].ID : p_item;
- emit_signal("id_pressed", id);
- emit_signal("index_pressed", p_item);
- //hide all parent PopupMenue's
+ //hide all parent PopupMenus
Node *next = get_parent();
PopupMenu *pop = Object::cast_to<PopupMenu>(next);
while (pop) {
@@ -1040,16 +1074,23 @@ 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
+ bool need_hide = true;
+
if (items[p_item].checkable_type) {
if (!hide_on_checkable_item_selection)
- return;
+ need_hide = false;
} else if (0 < items[p_item].max_states) {
if (!hide_on_multistate_item_selection)
- return;
+ need_hide = false;
} else if (!hide_on_item_selection)
- return;
+ need_hide = false;
- hide();
+ emit_signal("id_pressed", id);
+ emit_signal("index_pressed", p_item);
+
+ if (need_hide) {
+ hide();
+ }
}
void PopupMenu::remove_item(int p_idx) {
@@ -1062,13 +1103,18 @@ void PopupMenu::remove_item(int p_idx) {
items.remove(p_idx);
update();
+ minimum_size_changed();
}
-void PopupMenu::add_separator() {
+void PopupMenu::add_separator(const String &p_text) {
Item sep;
sep.separator = true;
sep.ID = -1;
+ if (p_text != String()) {
+ sep.text = p_text;
+ sep.xl_text = tr(p_text);
+ }
items.push_back(sep);
update();
}
@@ -1201,6 +1247,29 @@ bool PopupMenu::is_hide_on_multistate_item_selection() const {
return hide_on_multistate_item_selection;
}
+void PopupMenu::set_submenu_popup_delay(float p_time) {
+
+ if (p_time <= 0)
+ p_time = 0.01;
+
+ submenu_timer->set_wait_time(p_time);
+}
+
+float PopupMenu::get_submenu_popup_delay() const {
+
+ return submenu_timer->get_wait_time();
+}
+
+void PopupMenu::set_hide_on_window_lose_focus(bool p_enabled) {
+
+ hide_on_window_lose_focus = p_enabled;
+}
+
+bool PopupMenu::is_hide_on_window_lose_focus() const {
+
+ return hide_on_window_lose_focus;
+}
+
String PopupMenu::get_tooltip(const Point2 &p_pos) const {
int over = _get_mouse_over(p_pos);
@@ -1288,7 +1357,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_item", "idx"), &PopupMenu::remove_item);
- ClassDB::bind_method(D_METHOD("add_separator"), &PopupMenu::add_separator);
+ ClassDB::bind_method(D_METHOD("add_separator", "label"), &PopupMenu::add_separator, DEFVAL(String()));
ClassDB::bind_method(D_METHOD("clear"), &PopupMenu::clear);
ClassDB::bind_method(D_METHOD("_set_items"), &PopupMenu::_set_items);
@@ -1303,12 +1372,19 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hide_on_state_item_selection", "enable"), &PopupMenu::set_hide_on_multistate_item_selection);
ClassDB::bind_method(D_METHOD("is_hide_on_state_item_selection"), &PopupMenu::is_hide_on_multistate_item_selection);
+ ClassDB::bind_method(D_METHOD("set_submenu_popup_delay", "seconds"), &PopupMenu::set_submenu_popup_delay);
+ ClassDB::bind_method(D_METHOD("get_submenu_popup_delay"), &PopupMenu::get_submenu_popup_delay);
+
+ ClassDB::bind_method(D_METHOD("set_hide_on_window_lose_focus", "enable"), &PopupMenu::set_hide_on_window_lose_focus);
+ ClassDB::bind_method(D_METHOD("is_hide_on_window_lose_focus"), &PopupMenu::is_hide_on_window_lose_focus);
+
ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout);
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_PROPERTY(PropertyInfo(Variant::REAL, "submenu_popup_delay"), "set_submenu_popup_delay", "get_submenu_popup_delay");
ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID")));
ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "ID")));
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index d3ee9be1c0..a06a17c9fe 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -101,6 +101,7 @@ class PopupMenu : public Popup {
bool hide_on_item_selection;
bool hide_on_checkable_item_selection;
bool hide_on_multistate_item_selection;
+ bool hide_on_window_lose_focus;
Vector2 moved;
Array _get_items() const;
@@ -180,7 +181,7 @@ public:
void remove_item(int p_idx);
- void add_separator();
+ void add_separator(const String &p_text = String());
void clear();
@@ -202,8 +203,14 @@ public:
void set_hide_on_multistate_item_selection(bool p_enabled);
bool is_hide_on_multistate_item_selection() const;
+ void set_submenu_popup_delay(float p_time);
+ float get_submenu_popup_delay() const;
+
virtual void popup(const Rect2 &p_bounds = Rect2());
+ void set_hide_on_window_lose_focus(bool p_enabled);
+ bool is_hide_on_window_lose_focus() const;
+
PopupMenu();
~PopupMenu();
};
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 4062e48640..09d8664240 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -260,8 +260,8 @@ void Range::_bind_methods() {
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");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed");
}
void Range::set_use_rounded_values(bool p_enable) {
diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp
index 5e25f43daf..74e68598f4 100644
--- a/scene/gui/reference_rect.cpp
+++ b/scene/gui/reference_rect.cpp
@@ -39,9 +39,25 @@ void ReferenceRect::_notification(int p_what) {
if (!is_inside_tree())
return;
if (Engine::get_singleton()->is_editor_hint())
- draw_style_box(get_stylebox("border"), Rect2(Point2(), get_size()));
+ draw_rect(Rect2(Point2(), get_size()), border_color, false);
}
}
+void ReferenceRect::set_border_color(const Color &color) {
+ border_color = color;
+}
+
+Color ReferenceRect::get_border_color() const {
+ return border_color;
+}
+
+void ReferenceRect::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_border_color"), &ReferenceRect::get_border_color);
+ ClassDB::bind_method(D_METHOD("set_border_color", "color"), &ReferenceRect::set_border_color);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color");
+}
+
ReferenceRect::ReferenceRect() {
+ border_color = Color(1, 0, 0);
}
diff --git a/scene/gui/reference_rect.h b/scene/gui/reference_rect.h
index 473e348c85..9fad1a06b0 100644
--- a/scene/gui/reference_rect.h
+++ b/scene/gui/reference_rect.h
@@ -36,12 +36,17 @@
class ReferenceRect : public Control {
GDCLASS(ReferenceRect, Control);
+ Color border_color;
protected:
void _notification(int p_what);
+ static void _bind_methods();
public:
ReferenceRect();
+
+ void set_border_color(const Color &color);
+ Color get_border_color() const;
};
#endif // REFERENCE_RECT_H
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index f34559fc8d..a5f9bea1b1 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -149,7 +149,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (r_click_item)
*r_click_item = NULL;
}
- Line &l = p_frame->lines[p_line];
+ Line &l = p_frame->lines.write[p_line];
Item *it = l.from;
int line_ofs = 0;
@@ -324,7 +324,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
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)) {
+ if (_find_meta(text, &meta) && underline_meta) {
underline = true;
}
@@ -535,9 +535,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int idx = 0;
//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;
+ table->columns.write[i].min_width = 0;
+ table->columns.write[i].max_width = 0;
+ table->columns.write[i].width = 0;
}
//compute minimum width for each cell
const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs;
@@ -553,8 +553,8 @@ 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, 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);
+ table->columns.write[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width);
+ table->columns.write[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width);
}
idx++;
}
@@ -568,16 +568,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
for (int i = 0; i < table->columns.size(); i++) {
remaining_width -= table->columns[i].min_width;
if (table->columns[i].max_width > table->columns[i].min_width)
- table->columns[i].expand = true;
+ table->columns.write[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;
+ table->columns.write[i].width = table->columns[i].min_width;
if (table->columns[i].expand)
- table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
+ table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
table->total_width += table->columns[i].width + hseparation;
}
@@ -592,7 +592,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
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->columns.write[i].width = table->columns[i].max_width;
table->total_width -= dif;
total_ratio -= table->columns[i].expand_ratio;
}
@@ -606,7 +606,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
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->columns.write[i].width += incr;
table->total_width += incr;
}
}
@@ -626,8 +626,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int ly = 0;
_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
+ frame->lines.write[i].height_cache = ly; //actual height
+ frame->lines.write[i].height_accum_cache = ly; //actual height
}
idx++;
}
@@ -669,7 +669,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
yofs += frame->lines[i].height_cache;
if (p_mode == PROCESS_CACHE) {
- frame->lines[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache;
+ frame->lines.write[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache;
}
}
@@ -1253,6 +1253,9 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
//validate invalid lines
Size2 size = get_size();
+ if (fixed_width != -1) {
+ size.width = fixed_width;
+ }
Rect2 text_rect = _get_text_rect();
Color font_color_shadow = get_color("font_color_shadow");
bool use_outline = get_constant("shadow_as_outline");
@@ -1264,11 +1267,11 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
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(), font_color_shadow, use_outline, shadow_ofs);
- p_frame->lines[i].height_cache = y;
- p_frame->lines[i].height_accum_cache = y;
+ p_frame->lines.write[i].height_cache = y;
+ p_frame->lines.write[i].height_accum_cache = y;
if (i > 0)
- p_frame->lines[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache;
+ p_frame->lines.write[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache;
}
int total_height = 0;
@@ -1343,7 +1346,7 @@ void RichTextLabel::add_text(const String &p_text) {
_add_item(item, false);
current_frame->lines.resize(current_frame->lines.size() + 1);
if (item->type != ITEM_NEWLINE)
- current_frame->lines[current_frame->lines.size() - 1].from = item;
+ current_frame->lines.write[current_frame->lines.size() - 1].from = item;
_invalidate_current_line(current_frame);
}
@@ -1366,7 +1369,7 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline)
}
if (current_frame->lines[current_frame->lines.size() - 1].from == NULL) {
- current_frame->lines[current_frame->lines.size() - 1].from = p_item;
+ current_frame->lines.write[current_frame->lines.size() - 1].from = p_item;
}
p_item->line = current_frame->lines.size() - 1;
@@ -1428,7 +1431,7 @@ bool RichTextLabel::remove_line(const int p_line) {
_remove_item(current->subitems[lines], current->subitems[lines]->line, lines);
if (p_line == 0) {
- main->lines[0].from = main;
+ main->lines.write[0].from = main;
}
main->first_invalid_line = 0;
@@ -1507,8 +1510,8 @@ void RichTextLabel::push_table(int p_columns) {
item->columns.resize(p_columns);
item->total_width = 0;
for (int i = 0; i < item->columns.size(); i++) {
- item->columns[i].expand = false;
- item->columns[i].expand_ratio = 1;
+ item->columns.write[i].expand = false;
+ item->columns.write[i].expand_ratio = 1;
}
_add_item(item, true, true);
}
@@ -1518,8 +1521,8 @@ void RichTextLabel::set_table_column_expand(int p_column, bool p_expand, int p_r
ERR_FAIL_COND(current->type != ITEM_TABLE);
ItemTable *table = static_cast<ItemTable *>(current);
ERR_FAIL_INDEX(p_column, table->columns.size());
- table->columns[p_column].expand = p_expand;
- table->columns[p_column].expand_ratio = p_ratio;
+ table->columns.write[p_column].expand = p_expand;
+ table->columns.write[p_column].expand_ratio = p_ratio;
}
void RichTextLabel::push_cell() {
@@ -1533,7 +1536,7 @@ void RichTextLabel::push_cell() {
item->cell = true;
item->parent_line = item->parent_frame->lines.size() - 1;
item->lines.resize(1);
- item->lines[0].from = NULL;
+ item->lines.write[0].from = NULL;
item->first_invalid_line = 0;
}
@@ -2031,7 +2034,6 @@ void RichTextLabel::selection_copy() {
if (text != "") {
OS::get_singleton()->set_clipboard(text);
- //print_line("COPY: "+text);
}
}
@@ -2245,13 +2247,28 @@ int RichTextLabel::get_total_character_count() const {
return tc;
}
+void RichTextLabel::set_fixed_size_to_width(int p_width) {
+ fixed_width = p_width;
+ minimum_size_changed();
+}
+
+Size2 RichTextLabel::get_minimum_size() const {
+
+ if (fixed_width != -1) {
+ const_cast<RichTextLabel *>(this)->_validate_line_caches(main);
+ return Size2(fixed_width, const_cast<RichTextLabel *>(this)->get_content_height());
+ }
+
+ return Size2();
+}
+
RichTextLabel::RichTextLabel() {
main = memnew(ItemFrame);
main->index = 0;
current = main;
main->lines.resize(1);
- main->lines[0].from = main;
+ main->lines.write[0].from = main;
main->first_invalid_line = 0;
current_frame = main;
tab_size = 4;
@@ -2287,6 +2304,7 @@ RichTextLabel::RichTextLabel() {
percent_visible = 1;
visible_line_count = 0;
+ fixed_width = -1;
set_clip_contents(true);
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index af368af46a..06e9b8efe3 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -293,6 +293,8 @@ private:
void _update_all_lines();
+ int fixed_width;
+
protected:
void _notification(int p_what);
@@ -368,6 +370,9 @@ public:
void set_percent_visible(float p_percent);
float get_percent_visible() const;
+ void set_fixed_size_to_width(int p_width);
+ virtual Size2 get_minimum_size() const;
+
RichTextLabel();
~RichTextLabel();
};
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 6ec67aca6b..e5bd1c453d 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -257,9 +257,7 @@ void ScrollBar::_notification(int p_what) {
Point2 ofs;
- VisualServer *vs = VisualServer::get_singleton();
-
- vs->canvas_item_add_texture_rect(ci, Rect2(Point2(), decr->get_size()), decr->get_rid());
+ decr->draw(ci, Point2());
if (orientation == HORIZONTAL)
ofs.x += decr->get_width();
@@ -280,7 +278,7 @@ void ScrollBar::_notification(int p_what) {
else
ofs.height += area.height;
- vs->canvas_item_add_texture_rect(ci, Rect2(ofs, decr->get_size()), incr->get_rid());
+ incr->draw(ci, ofs);
Rect2 grabber_rect;
if (orientation == HORIZONTAL) {
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 46215c9277..b820e2eafd 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -65,11 +65,12 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
} else {
grab.active = false;
}
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
-
- set_value(get_value() + get_step());
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
- set_value(get_value() - get_step());
+ } else if (scrollable) {
+ if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ set_value(get_value() + get_step());
+ } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ set_value(get_value() - get_step());
+ }
}
}
@@ -247,6 +248,16 @@ bool Slider::is_editable() const {
return editable;
}
+void Slider::set_scrollable(bool p_scrollable) {
+
+ scrollable = p_scrollable;
+}
+
+bool Slider::is_scrollable() const {
+
+ return scrollable;
+}
+
void Slider::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &Slider::_gui_input);
@@ -258,8 +269,11 @@ void Slider::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_editable", "editable"), &Slider::set_editable);
ClassDB::bind_method(D_METHOD("is_editable"), &Slider::is_editable);
+ ClassDB::bind_method(D_METHOD("set_scrollable", "scrollable"), &Slider::set_scrollable);
+ ClassDB::bind_method(D_METHOD("is_scrollable"), &Slider::is_scrollable);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrollable"), "set_scrollable", "is_scrollable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tick_count", PROPERTY_HINT_RANGE, "0,4096,1"), "set_ticks", "get_ticks");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ticks_on_borders"), "set_ticks_on_borders", "get_ticks_on_borders");
ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
@@ -272,5 +286,6 @@ Slider::Slider(Orientation p_orientation) {
ticks = 0;
custom_step = -1;
editable = true;
+ scrollable = true;
set_focus_mode(FOCUS_ALL);
}
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index e77a0b7423..4d02348159 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -48,6 +48,7 @@ class Slider : public Range {
Orientation orientation;
float custom_step;
bool editable;
+ bool scrollable;
protected:
void _gui_input(Ref<InputEvent> p_event);
@@ -70,6 +71,9 @@ public:
void set_editable(bool p_editable);
bool is_editable() const;
+ void set_scrollable(bool p_scrollable);
+ bool is_scrollable() const;
+
Slider(Orientation p_orientation = VERTICAL);
};
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 4f72b5c6ed..c30fa96327 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -407,7 +407,7 @@ void TabContainer::_child_renamed_callback() {
void TabContainer::add_child_notify(Node *p_child) {
- Control::add_child_notify(p_child);
+ Container::add_child_notify(p_child);
Control *c = Object::cast_to<Control>(p_child);
if (!c)
@@ -515,7 +515,7 @@ Control *TabContainer::get_current_tab_control() const {
void TabContainer::remove_child_notify(Node *p_child) {
- Control::remove_child_notify(p_child);
+ Container::remove_child_notify(p_child);
call_deferred("_update_current_tab");
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 1afe5f7541..8a3c9d2bb2 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -31,11 +31,11 @@
#ifndef TAB_CONTAINER_H
#define TAB_CONTAINER_H
-#include "scene/gui/control.h"
+#include "scene/gui/container.h"
#include "scene/gui/popup.h"
-class TabContainer : public Control {
+class TabContainer : public Container {
- GDCLASS(TabContainer, Control);
+ GDCLASS(TabContainer, Container);
public:
enum TabAlign {
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index b114264de1..2075f7ce70 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -189,7 +189,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && (mb->get_button_index() == BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == BUTTON_RIGHT))) {
// clicks
Point2 pos(mb->get_position().x, mb->get_position().y);
@@ -286,7 +286,7 @@ void Tabs::_notification(int p_what) {
for (int i = 0; i < tabs.size(); i++) {
- tabs[i].ofs_cache = mw;
+ tabs.write[i].ofs_cache = mw;
mw += get_tab_width(i);
}
@@ -314,7 +314,7 @@ void Tabs::_notification(int p_what) {
if (i < offset)
continue;
- tabs[i].ofs_cache = w;
+ tabs.write[i].ofs_cache = w;
int lsize = tabs[i].size_cache;
@@ -379,7 +379,7 @@ void Tabs::_notification(int p_what) {
rb->draw(ci, Point2i(w + style->get_margin(MARGIN_LEFT), rb_rect.position.y + style->get_margin(MARGIN_TOP)));
w += rb->get_width();
- tabs[i].rb_rect = rb_rect;
+ tabs.write[i].rb_rect = rb_rect;
}
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) {
@@ -403,7 +403,7 @@ void Tabs::_notification(int p_what) {
cb->draw(ci, Point2i(w + style->get_margin(MARGIN_LEFT), cb_rect.position.y + style->get_margin(MARGIN_TOP)));
w += cb->get_width();
- tabs[i].cb_rect = cb_rect;
+ tabs.write[i].cb_rect = cb_rect;
}
w += sb->get_margin(MARGIN_RIGHT);
@@ -471,7 +471,7 @@ bool Tabs::get_offset_buttons_visible() const {
void Tabs::set_tab_title(int p_tab, const String &p_title) {
ERR_FAIL_INDEX(p_tab, tabs.size());
- tabs[p_tab].text = p_title;
+ tabs.write[p_tab].text = p_title;
update();
minimum_size_changed();
}
@@ -485,7 +485,7 @@ String Tabs::get_tab_title(int p_tab) const {
void Tabs::set_tab_icon(int p_tab, const Ref<Texture> &p_icon) {
ERR_FAIL_INDEX(p_tab, tabs.size());
- tabs[p_tab].icon = p_icon;
+ tabs.write[p_tab].icon = p_icon;
update();
minimum_size_changed();
}
@@ -499,7 +499,7 @@ Ref<Texture> Tabs::get_tab_icon(int p_tab) const {
void Tabs::set_tab_disabled(int p_tab, bool p_disabled) {
ERR_FAIL_INDEX(p_tab, tabs.size());
- tabs[p_tab].disabled = p_disabled;
+ tabs.write[p_tab].disabled = p_disabled;
update();
}
bool Tabs::get_tab_disabled(int p_tab) const {
@@ -511,7 +511,7 @@ bool Tabs::get_tab_disabled(int p_tab) const {
void Tabs::set_tab_right_button(int p_tab, const Ref<Texture> &p_right_button) {
ERR_FAIL_INDEX(p_tab, tabs.size());
- tabs[p_tab].right_button = p_right_button;
+ tabs.write[p_tab].right_button = p_right_button;
_update_cache();
update();
minimum_size_changed();
@@ -536,9 +536,9 @@ void Tabs::_update_cache() {
int size_fixed = 0;
int count_resize = 0;
for (int i = 0; i < tabs.size(); i++) {
- tabs[i].ofs_cache = mw;
- tabs[i].size_cache = get_tab_width(i);
- tabs[i].size_text = font->get_string_size(tabs[i].text).width;
+ tabs.write[i].ofs_cache = mw;
+ tabs.write[i].size_cache = get_tab_width(i);
+ tabs.write[i].size_text = font->get_string_size(tabs[i].text).width;
mw += tabs[i].size_cache;
if (tabs[i].size_cache <= min_width || i == current) {
size_fixed += tabs[i].size_cache;
@@ -579,9 +579,9 @@ void Tabs::_update_cache() {
lsize = m_width;
}
}
- tabs[i].ofs_cache = w;
- tabs[i].size_cache = lsize;
- tabs[i].size_text = slen;
+ tabs.write[i].ofs_cache = w;
+ tabs.write[i].size_cache = lsize;
+ tabs.write[i].size_text = slen;
w += lsize;
}
}
@@ -920,6 +920,14 @@ int Tabs::get_tabs_rearrange_group() const {
return tabs_rearrange_group;
}
+void Tabs::set_select_with_rmb(bool p_enabled) {
+ select_with_rmb = p_enabled;
+}
+
+bool Tabs::get_select_with_rmb() const {
+ return select_with_rmb;
+}
+
void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input);
@@ -950,6 +958,9 @@ void Tabs::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("set_select_with_rmb", "enabled"), &Tabs::set_select_with_rmb);
+ ClassDB::bind_method(D_METHOD("get_select_with_rmb"), &Tabs::get_select_with_rmb);
+
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("right_button_pressed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_close", PropertyInfo(Variant::INT, "tab")));
@@ -988,6 +999,8 @@ Tabs::Tabs() {
offset = 0;
max_drawn_tab = 0;
+ select_with_rmb = false;
+
min_width = 0;
scrolling_enabled = true;
buttons_visible = false;
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 3b38e7f2cb..e204f4364b 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -83,6 +83,8 @@ private:
int rb_hover;
bool rb_pressing;
+ bool select_with_rmb;
+
int cb_hover;
bool cb_pressing;
CloseButtonDisplayPolicy cb_displaypolicy;
@@ -150,6 +152,9 @@ public:
void set_tabs_rearrange_group(int p_group_id);
int get_tabs_rearrange_group() const;
+ void set_select_with_rmb(bool p_enabled);
+ bool get_select_with_rmb() 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 215ba0271f..ec98b01ced 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -127,13 +127,13 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
w += get_char_width(str[i], str[i + 1], w);
}
- text[p_line].width_cache = w;
+ text.write[p_line].width_cache = w;
- text[p_line].wrap_amount_cache = -1;
+ text.write[p_line].wrap_amount_cache = -1;
//update regions
- text[p_line].region_info.clear();
+ text.write[p_line].region_info.clear();
for (int i = 0; i < len; i++) {
@@ -172,7 +172,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
ColorRegionInfo cri;
cri.end = false;
cri.region = j;
- text[p_line].region_info[i] = cri;
+ text.write[p_line].region_info[i] = cri;
i += lr - 1;
break;
@@ -200,7 +200,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
ColorRegionInfo cri;
cri.end = true;
cri.region = j;
- text[p_line].region_info[i] = cri;
+ text.write[p_line].region_info[i] = cri;
i += lr - 1;
break;
@@ -236,7 +236,7 @@ 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;
+ text.write[p_line].wrap_amount_cache = p_wrap_amount;
}
int TextEdit::Text::get_line_wrap_amount(int p_line) const {
@@ -249,14 +249,14 @@ int TextEdit::Text::get_line_wrap_amount(int p_line) const {
void TextEdit::Text::clear_width_cache() {
for (int i = 0; i < text.size(); i++) {
- text[i].width_cache = -1;
+ text.write[i].width_cache = -1;
}
}
void TextEdit::Text::clear_wrap_cache() {
for (int i = 0; i < text.size(); i++) {
- text[i].wrap_amount_cache = -1;
+ text.write[i].wrap_amount_cache = -1;
}
}
@@ -281,15 +281,16 @@ 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;
+ text.write[p_line].width_cache = -1;
+ text.write[p_line].wrap_amount_cache = -1;
+ text.write[p_line].data = p_text;
}
void TextEdit::Text::insert(int p_at, const String &p_text) {
Line line;
line.marked = false;
+ line.safe = false;
line.breakpoint = false;
line.hidden = false;
line.width_cache = -1;
@@ -336,10 +337,6 @@ void TextEdit::_update_scrollbars() {
int hscroll_rows = ((hmin.height - 1) / get_row_height()) + 1;
int visible_rows = get_visible_rows();
- 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;
@@ -426,6 +423,9 @@ void TextEdit::_update_scrollbars() {
void TextEdit::_click_selection_held() {
+ // Warning: is_mouse_button_pressed(BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
+ // and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem.
+ // I'm unsure if there's an actual fix that doesn't have a ton of side effects.
if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) {
switch (selection.selecting_mode) {
case Selection::MODE_POINTER: {
@@ -455,7 +455,7 @@ void TextEdit::_update_selection_mode_pointer() {
select(selection.selecting_line, selection.selecting_column, row, col);
cursor_set_line(row, false);
- cursor_set_column(col, false);
+ cursor_set_column(col);
update();
click_select_held->start();
@@ -496,21 +496,24 @@ void TextEdit::_update_selection_mode_word() {
selection.selected_word_beg = beg;
selection.selected_word_end = end;
selection.selected_word_origin = beg;
+ cursor_set_line(selection.to_line, false);
cursor_set_column(selection.to_column);
} else {
if ((col <= selection.selected_word_origin && row == selection.selecting_line) || row < selection.selecting_line) {
selection.selecting_column = selection.selected_word_end;
select(row, beg, selection.selecting_line, selection.selected_word_end);
+ cursor_set_line(selection.from_line, false);
cursor_set_column(selection.from_column);
} else {
selection.selecting_column = selection.selected_word_beg;
select(selection.selecting_line, selection.selected_word_beg, row, end);
+ cursor_set_line(selection.to_line, false);
cursor_set_column(selection.to_column);
}
}
- cursor_set_line(row, false);
update();
+
click_select_held->start();
}
@@ -531,7 +534,7 @@ void TextEdit::_update_selection_mode_line() {
selection.selecting_column = 0;
col = text[row].length();
}
- cursor_set_column(0, false);
+ cursor_set_column(0);
select(selection.selecting_line, selection.selecting_column, row, col);
update();
@@ -960,12 +963,13 @@ void TextEdit::_notification(int p_what) {
// draw line numbers
if (cache.line_number_w) {
+ int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2;
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);
+ cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, text.is_safe(line) ? cache.safe_line_number_color : cache.line_number_color);
}
}
@@ -1088,12 +1092,13 @@ void TextEdit::_notification(int p_what) {
}
if (brace_matching_enabled) {
+ int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2;
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);
+ drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
if ((brace_close_match_line == line && brace_close_match_column == last_wrap_column + j) ||
@@ -1101,7 +1106,7 @@ void TextEdit::_notification(int p_what) {
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);
+ drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
}
@@ -1143,10 +1148,18 @@ void TextEdit::_notification(int p_what) {
if (ime_text.length() == 0) {
if (draw_caret) {
if (insert_mode) {
- int caret_h = (block_caret) ? 4 : 1;
+#ifdef TOOLS_ENABLED
+ int caret_h = (block_caret) ? 4 : 2 * EDSCALE;
+#else
+ int caret_h = (block_caret) ? 4 : 2;
+#endif
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;
+#ifdef TOOLS_ENABLED
+ caret_w = (block_caret) ? caret_w : 2 * EDSCALE;
+#else
+ caret_w = (block_caret) ? caret_w : 2;
+#endif
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
}
}
@@ -1161,9 +1174,15 @@ void TextEdit::_notification(int p_what) {
}
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);
+ int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2;
+ int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + 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);
+ float line_width = 1.0;
+#ifdef TOOLS_ENABLED
+ line_width *= EDSCALE;
+#endif
+
+ draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, line_width), 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;
@@ -1218,11 +1237,19 @@ void TextEdit::_notification(int p_what) {
if (draw_caret) {
if (insert_mode) {
int char_w = cache.font->get_char_size(' ').width;
- int caret_h = (block_caret) ? 4 : 1;
+#ifdef TOOLS_ENABLED
+ int caret_h = (block_caret) ? 4 : 2 * EDSCALE;
+#else
+ int caret_h = (block_caret) ? 4 : 2;
+#endif
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;
+#ifdef TOOLS_ENABLED
+ int caret_w = (block_caret) ? char_w : 2 * EDSCALE;
+#else
+ int caret_w = (block_caret) ? char_w : 2;
+#endif
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
}
}
@@ -1528,8 +1555,11 @@ void TextEdit::backspace_at_cursor() {
if (is_line_hidden(cursor.line))
set_line_as_hidden(prev_line, true);
- if (is_line_set_as_breakpoint(cursor.line))
+ if (is_line_set_as_breakpoint(cursor.line)) {
+ if (!text.is_breakpoint(prev_line))
+ emit_signal("breakpoint_toggled", prev_line);
set_line_as_breakpoint(prev_line, true);
+ }
if (auto_brace_completion_enabled &&
cursor.column > 0 &&
@@ -1665,9 +1695,11 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
if (is_wrap_enabled() || is_hiding_enabled()) {
- 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);
+ int f_ofs = num_lines_from_rows(first_vis_line, cursor.wrap_ofs, rows + (1 * SGN(rows)), wrap_index) - 1;
+ if (rows < 0)
+ row = first_vis_line - f_ofs;
+ else
+ row = first_vis_line + f_ofs;
}
if (row < 0)
@@ -2168,9 +2200,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
k->set_shift(false);
}
- if (!k->get_command()) {
- _reset_caret_blink_timer();
- }
+ _reset_caret_blink_timer();
// save here for insert mode, just in case it is cleared in the following section
bool had_selection = selection.active;
@@ -3301,22 +3331,37 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
ERR_FAIL_INDEX(p_line, text.size());
ERR_FAIL_COND(p_char < 0);
- /* STEP 1 add spaces if the char is greater than the end of the line */
+ /* STEP 1 remove \r from source text and separate in substrings */
+
+ Vector<String> substrings = p_text.replace("\r", "").split("\n");
+
+ /* STEP 2 fire breakpoint_toggled signals */
+
+ // Is this just a new empty line?
+ bool shift_first_line = p_char == 0 && p_text.replace("\r", "") == "\n";
+
+ int i = p_line + !shift_first_line;
+ int lines = substrings.size() - 1;
+ for (; i < text.size(); i++) {
+ if (text.is_breakpoint(i)) {
+ if ((i - lines < p_line || !text.is_breakpoint(i - lines)) || (i - lines == p_line && !shift_first_line))
+ emit_signal("breakpoint_toggled", i);
+ if (i + lines >= text.size() || !text.is_breakpoint(i + lines))
+ emit_signal("breakpoint_toggled", i + lines);
+ }
+ }
+
+ /* STEP 3 add spaces if the char is greater than the end of the line */
while (p_char > text[p_line].length()) {
text.set(p_line, text[p_line] + String::chr(' '));
}
- /* STEP 2 separate dest string in pre and post text */
+ /* STEP 4 separate dest string in pre and post text */
String preinsert_text = text[p_line].substr(0, p_char);
String postinsert_text = text[p_line].substr(p_char, text[p_line].size());
- /* STEP 3 remove \r from source text and separate in substrings */
-
- //buh bye \r and split
- Vector<String> substrings = p_text.replace("\r", "").split("\n");
-
for (int i = 0; i < substrings.size(); i++) {
//insert the substrings
@@ -3334,9 +3379,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
}
}
- // if we are just making a new empty line, reset breakpoints and hidden status
- if (p_char == 0 && p_text.replace("\r", "") == "\n") {
-
+ if (shift_first_line) {
text.set_breakpoint(p_line + 1, text.is_breakpoint(p_line));
text.set_hidden(p_line + 1, text.is_hidden(p_line));
text.set_breakpoint(p_line, false);
@@ -3392,11 +3435,20 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
String pre_text = text[p_from_line].substr(0, p_from_column);
String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length());
- for (int i = p_from_line; i < p_to_line; i++) {
+ int lines = p_to_line - p_from_line;
- text.remove(p_from_line + 1);
+ for (int i = p_from_line + 1; i < text.size(); i++) {
+ if (text.is_breakpoint(i)) {
+ if (i + lines >= text.size() || !text.is_breakpoint(i + lines))
+ emit_signal("breakpoint_toggled", i);
+ if (i > p_to_line && (i - lines < 0 || !text.is_breakpoint(i - lines)))
+ emit_signal("breakpoint_toggled", i - lines);
+ }
}
+ for (int i = p_from_line; i < p_to_line; i++) {
+ text.remove(p_from_line + 1);
+ }
text.set(p_from_line, pre_text + post_text);
text.set_line_wrap_amount(p_from_line, -1);
@@ -3762,7 +3814,6 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
}
// 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;
}
@@ -4277,6 +4328,7 @@ void TextEdit::_update_caches() {
cache.caret_color = get_color("caret_color");
cache.caret_background_color = get_color("caret_background_color");
cache.line_number_color = get_color("line_number_color");
+ cache.safe_line_number_color = get_color("safe_line_number_color");
cache.font_color = get_color("font_color");
cache.font_selected_color = get_color("font_selected_color");
cache.keyword_color = get_color("keyword_color");
@@ -4295,7 +4347,11 @@ void TextEdit::_update_caches() {
cache.search_result_border_color = get_color("search_result_border_color");
cache.symbol_color = get_color("symbol_color");
cache.background_color = get_color("background_color");
+#ifdef TOOLS_ENABLED
+ cache.line_spacing = get_constant("line_spacing") * EDSCALE;
+#else
cache.line_spacing = get_constant("line_spacing");
+#endif
cache.row_height = cache.font->get_height() + cache.line_spacing;
cache.tab_icon = get_icon("tab");
cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons");
@@ -4848,6 +4904,17 @@ void TextEdit::set_line_as_marked(int p_line, bool p_marked) {
update();
}
+void TextEdit::set_line_as_safe(int p_line, bool p_safe) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ text.set_safe(p_line, p_safe);
+ update();
+}
+
+bool TextEdit::is_line_set_as_safe(int p_line) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), false);
+ return text.is_safe(p_line);
+}
+
bool TextEdit::is_line_set_as_breakpoint(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), false);
@@ -4869,6 +4936,24 @@ void TextEdit::get_breakpoints(List<int> *p_breakpoints) const {
}
}
+Array TextEdit::get_breakpoints_array() const {
+
+ Array arr;
+ for (int i = 0; i < text.size(); i++) {
+ if (text.is_breakpoint(i))
+ arr.append(i);
+ }
+ return arr;
+}
+
+void TextEdit::remove_breakpoints() {
+ for (int i = 0; i < text.size(); i++) {
+ if (text.is_breakpoint(i))
+ /* Should "breakpoint_toggled" be fired when breakpoints are removed this way? */
+ text.set_breakpoint(i, false);
+ }
+}
+
void TextEdit::set_line_as_hidden(int p_line, bool p_hidden) {
ERR_FAIL_INDEX(p_line, text.size());
@@ -5451,9 +5536,8 @@ int TextEdit::get_last_visible_line() const {
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;
+ num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi);
return wi;
}
@@ -5538,7 +5622,17 @@ void TextEdit::_confirm_completion() {
cursor_set_column(cursor.column - completion_base.length(), false);
insert_text_at_cursor(completion_current);
- if (completion_current.ends_with("(") && auto_brace_completion_enabled) {
+ // When inserted into the middle of an existing string, don't add an unnecessary quote
+ String line = text[cursor.line];
+ CharType next_char = line[cursor.column];
+ CharType last_completion_char = completion_current[completion_current.length() - 1];
+
+ if ((last_completion_char == '"' || last_completion_char == '\'') &&
+ last_completion_char == next_char) {
+ _base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
+ }
+
+ if (last_completion_char == '(' && auto_brace_completion_enabled) {
insert_text_at_cursor(")");
cursor.column--;
}
@@ -5546,6 +5640,10 @@ void TextEdit::_confirm_completion() {
end_complex_operation();
_cancel_completion();
+
+ if (last_completion_char == '(') {
+ query_code_comple();
+ }
}
void TextEdit::_cancel_code_hint() {
@@ -5598,15 +5696,12 @@ void TextEdit::_update_completion_candidates() {
bool pre_keyword = false;
bool cancel = false;
- //print_line("inquote: "+itos(inquote)+"first quote "+itos(first_quote)+" cofs-1 "+itos(cofs-1));
if (!inquote && first_quote == cofs - 1) {
//no completion here
- //print_line("cancel!");
cancel = true;
} else if (inquote && first_quote != -1) {
s = l.substr(first_quote, cofs - first_quote);
- //print_line("s: 1"+s);
} else if (cofs > 0 && l[cofs - 1] == ' ') {
int kofs = cofs - 1;
String kw;
@@ -5619,7 +5714,6 @@ void TextEdit::_update_completion_candidates() {
}
pre_keyword = keywords.has(kw);
- //print_line("KW "+kw+"? "+itos(pre_keyword));
} else {
@@ -5658,43 +5752,26 @@ void TextEdit::_update_completion_candidates() {
for (int i = 0; i < completion_strings.size(); i++) {
if (single_quote && completion_strings[i].is_quoted()) {
- completion_strings[i] = completion_strings[i].unquote().quote("'");
+ completion_strings.write[i] = completion_strings[i].unquote().quote("'");
}
- if (s == completion_strings[i]) {
- // A perfect match, stop completion
- _cancel_completion();
- return;
+ if (completion_strings[i].begins_with(s)) {
+ completion_options.push_back(completion_strings[i]);
}
+ }
- if (s.is_subsequence_ofi(completion_strings[i])) {
- // don't remove duplicates if no input is provided
- if (s != "" && completion_options.find(completion_strings[i]) != -1) {
- continue;
- }
- // Calculate the similarity to keep completions in good order
- float similarity;
- if (completion_strings[i].to_lower().begins_with(s.to_lower())) {
- // Substrings are the best candidates
- similarity = 1.1;
- } else {
- // Otherwise compute the similarity
- similarity = s.to_lower().similarity(completion_strings[i].to_lower());
+ if (completion_options.size() == 0) {
+ for (int i = 0; i < completion_strings.size(); i++) {
+ if (s.is_subsequence_of(completion_strings[i])) {
+ completion_options.push_back(completion_strings[i]);
}
+ }
+ }
- int comp_size = completion_options.size();
- if (comp_size == 0) {
+ if (completion_options.size() == 0) {
+ for (int i = 0; i < completion_strings.size(); i++) {
+ if (s.is_subsequence_ofi(completion_strings[i])) {
completion_options.push_back(completion_strings[i]);
- sim_cache.push_back(similarity);
- } else {
- float comp_sim;
- int pos = 0;
- do {
- comp_sim = sim_cache[pos++];
- } while (pos < comp_size && similarity < comp_sim);
- pos = similarity > comp_sim ? pos - 1 : pos; // Pos will be off by one
- completion_options.insert(pos, completion_strings[i]);
- sim_cache.insert(pos, similarity);
}
}
}
@@ -5702,7 +5779,12 @@ void TextEdit::_update_completion_candidates() {
if (completion_options.size() == 0) {
//no options to complete, cancel
_cancel_completion();
+ return;
+ }
+ if (completion_options.size() == 1 && s == completion_options[0]) {
+ // A perfect match, stop completion
+ _cancel_completion();
return;
}
@@ -5765,18 +5847,23 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
if (select_word(s, col, beg, end)) {
bool inside_quotes = false;
+ char selected_quote = '\0';
int qbegin = 0, qend = 0;
for (int i = 0; i < s.length(); i++) {
- if (s[i] == '"') {
- if (inside_quotes) {
- qend = i;
- inside_quotes = false;
- if (col >= qbegin && col <= qend) {
- return s.substr(qbegin, qend - qbegin);
+ if (s[i] == '"' || s[i] == '\'') {
+ if (i == 0 || s[i - 1] != '\\') {
+ if (inside_quotes && selected_quote == s[i]) {
+ qend = i;
+ inside_quotes = false;
+ selected_quote = '\0';
+ if (col >= qbegin && col <= qend) {
+ return s.substr(qbegin, qend - qbegin);
+ }
+ } else if (!inside_quotes) {
+ qbegin = i + 1;
+ inside_quotes = true;
+ selected_quote = s[i];
}
- } else {
- qbegin = i + 1;
- inside_quotes = true;
}
}
}
@@ -5857,12 +5944,12 @@ void TextEdit::set_line_length_guideline_column(int p_column) {
update();
}
-void TextEdit::set_draw_breakpoint_gutter(bool p_draw) {
+void TextEdit::set_breakpoint_gutter_enabled(bool p_draw) {
draw_breakpoint_gutter = p_draw;
update();
}
-bool TextEdit::is_drawing_breakpoint_gutter() const {
+bool TextEdit::is_breakpoint_gutter_enabled() const {
return draw_breakpoint_gutter;
}
@@ -6045,6 +6132,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers);
ClassDB::bind_method(D_METHOD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled);
+ ClassDB::bind_method(D_METHOD("set_breakpoint_gutter_enabled", "enable"), &TextEdit::set_breakpoint_gutter_enabled);
+ ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled);
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);
@@ -6083,11 +6172,15 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option);
ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu);
+ ClassDB::bind_method(D_METHOD("get_breakpoints"), &TextEdit::get_breakpoints_array);
+ ClassDB::bind_method(D_METHOD("remove_breakpoints"), &TextEdit::remove_breakpoints);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "readonly"), "set_readonly", "is_readonly");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "breakpoint_gutter"), "set_breakpoint_gutter_enabled", "is_breakpoint_gutter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
@@ -6308,7 +6401,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
}
// 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) {
+ if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'f') && !in_word && prev_is_number && !is_number) {
is_number = true;
is_symbol = false;
is_char = false;
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 5c82d1ac20..19b5d574c6 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -76,6 +76,7 @@ public:
bool marked : 1;
bool breakpoint : 1;
bool hidden : 1;
+ bool safe : 1;
int wrap_amount_cache : 24;
Map<int, ColorRegionInfo> region_info;
String data;
@@ -100,12 +101,14 @@ public:
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; }
+ void set_marked(int p_line, bool p_marked) { text.write[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; }
+ void set_breakpoint(int p_line, bool p_breakpoint) { text.write[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; }
+ void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; }
bool is_hidden(int p_line) const { return text[p_line].hidden; }
+ void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; }
+ bool is_safe(int p_line) const { return text[p_line].safe; }
void insert(int p_at, const String &p_text);
void remove(int p_at);
int size() const { return text.size(); }
@@ -165,6 +168,7 @@ private:
Color caret_color;
Color caret_background_color;
Color line_number_color;
+ Color safe_line_number_color;
Color font_color;
Color font_selected_color;
Color keyword_color;
@@ -472,7 +476,11 @@ public:
void set_line_as_marked(int p_line, bool p_marked);
void set_line_as_breakpoint(int p_line, bool p_breakpoint);
bool is_line_set_as_breakpoint(int p_line) const;
+ void set_line_as_safe(int p_line, bool p_safe);
+ bool is_line_set_as_safe(int p_line) const;
void get_breakpoints(List<int> *p_breakpoints) const;
+ Array get_breakpoints_array() const;
+ void remove_breakpoints();
void set_line_as_hidden(int p_line, bool p_hidden);
bool is_line_hidden(int p_line) const;
@@ -632,8 +640,8 @@ public:
void set_show_line_length_guideline(bool p_show);
void set_line_length_guideline_column(int p_column);
- void set_draw_breakpoint_gutter(bool p_draw);
- bool is_drawing_breakpoint_gutter() const;
+ void set_breakpoint_gutter_enabled(bool p_draw);
+ bool is_breakpoint_gutter_enabled() const;
void set_breakpoint_gutter_width(int p_gutter_width);
int get_breakpoint_gutter_width() const;
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index 82d983184b..ff90576c1b 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -266,6 +266,8 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F
}
}
+ p_texture->get_rect_region(dst_rect, src_rect, dst_rect, src_rect);
+
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::NINE_PATCH_STRETCH, VS::NINE_PATCH_STRETCH, true, p_modulate);
}
@@ -309,15 +311,23 @@ void TextureProgress::_notification(int p_what) {
draw_texture_rect_region(progress, region, region, tint_progress);
} break;
case FILL_CLOCKWISE:
- case FILL_COUNTER_CLOCKWISE: {
+ case FILL_COUNTER_CLOCKWISE:
+ case FILL_CLOCKWISE_AND_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, tint_progress);
} else if (val != 0) {
Array pts;
- float direction = mode == FILL_CLOCKWISE ? 1 : -1;
- float start = rad_init_angle / 360;
+ float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1;
+ float start;
+
+ if (mode == FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE) {
+ start = rad_init_angle / 360 - val / 2;
+ } else {
+ start = rad_init_angle / 360;
+ }
+
float end = start + direction * val;
pts.append(start);
pts.append(end);
@@ -351,6 +361,14 @@ void TextureProgress::_notification(int p_what) {
draw_line(p - Point2(0, 8), p + Point2(0, 8), Color(0.9, 0.5, 0.5), 2);
}
} break;
+ case FILL_BILINEAR_LEFT_AND_RIGHT: {
+ Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y));
+ draw_texture_rect_region(progress, region, region, tint_progress);
+ } break;
+ case FILL_BILINEAR_TOP_AND_BOTTOM: {
+ Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio()));
+ draw_texture_rect_region(progress, region, region, tint_progress);
+ } 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)), tint_progress);
}
@@ -364,7 +382,7 @@ void TextureProgress::_notification(int p_what) {
}
void TextureProgress::set_fill_mode(int p_fill) {
- ERR_FAIL_INDEX(p_fill, 6);
+ ERR_FAIL_INDEX(p_fill, 9);
mode = (FillMode)p_fill;
update();
}
@@ -446,7 +464,7 @@ void TextureProgress::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_under_texture", "get_under_texture");
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_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and 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");
@@ -468,6 +486,9 @@ void TextureProgress::_bind_methods() {
BIND_ENUM_CONSTANT(FILL_BOTTOM_TO_TOP);
BIND_ENUM_CONSTANT(FILL_CLOCKWISE);
BIND_ENUM_CONSTANT(FILL_COUNTER_CLOCKWISE);
+ BIND_ENUM_CONSTANT(FILL_BILINEAR_LEFT_AND_RIGHT);
+ BIND_ENUM_CONSTANT(FILL_BILINEAR_TOP_AND_BOTTOM);
+ BIND_ENUM_CONSTANT(FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE);
}
TextureProgress::TextureProgress() {
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h
index 34158b5db5..a11e55234a 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress.h
@@ -52,7 +52,10 @@ public:
FILL_TOP_TO_BOTTOM,
FILL_BOTTOM_TO_TOP,
FILL_CLOCKWISE,
- FILL_COUNTER_CLOCKWISE
+ FILL_COUNTER_CLOCKWISE,
+ FILL_BILINEAR_LEFT_AND_RIGHT,
+ FILL_BILINEAR_TOP_AND_BOTTOM,
+ FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE
};
void set_fill_mode(int p_fill);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 1d27612766..eaf7ad7670 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -121,7 +121,7 @@ void TreeItem::_cell_deselected(int p_cell) {
void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
ERR_FAIL_INDEX(p_column, cells.size());
- Cell &c = cells[p_column];
+ Cell &c = cells.write[p_column];
c.mode = p_mode;
c.min = 0;
c.max = 100;
@@ -144,7 +144,7 @@ TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const {
void TreeItem::set_checked(int p_column, bool p_checked) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].checked = p_checked;
+ cells.write[p_column].checked = p_checked;
_changed_notify(p_column);
}
@@ -157,22 +157,22 @@ bool TreeItem::is_checked(int p_column) const {
void TreeItem::set_text(int p_column, String p_text) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].text = p_text;
+ cells.write[p_column].text = p_text;
if (cells[p_column].mode == TreeItem::CELL_MODE_RANGE || cells[p_column].mode == TreeItem::CELL_MODE_RANGE_EXPRESSION) {
Vector<String> strings = p_text.split(",");
- cells[p_column].min = INT_MAX;
- cells[p_column].max = INT_MIN;
+ cells.write[p_column].min = INT_MAX;
+ cells.write[p_column].max = INT_MIN;
for (int i = 0; i < strings.size(); i++) {
int value = i;
if (!strings[i].get_slicec(':', 1).empty()) {
value = strings[i].get_slicec(':', 1).to_int();
}
- cells[p_column].min = MIN(cells[p_column].min, value);
- cells[p_column].max = MAX(cells[p_column].max, value);
+ cells.write[p_column].min = MIN(cells[p_column].min, value);
+ cells.write[p_column].max = MAX(cells[p_column].max, value);
}
- cells[p_column].step = 0;
+ cells.write[p_column].step = 0;
}
_changed_notify(p_column);
}
@@ -186,7 +186,7 @@ String TreeItem::get_text(int p_column) const {
void TreeItem::set_suffix(int p_column, String p_suffix) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].suffix = p_suffix;
+ cells.write[p_column].suffix = p_suffix;
_changed_notify(p_column);
}
@@ -200,7 +200,7 @@ String TreeItem::get_suffix(int p_column) const {
void TreeItem::set_icon(int p_column, const Ref<Texture> &p_icon) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].icon = p_icon;
+ cells.write[p_column].icon = p_icon;
_changed_notify(p_column);
}
@@ -213,7 +213,7 @@ Ref<Texture> TreeItem::get_icon(int p_column) const {
void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].icon_region = p_icon_region;
+ cells.write[p_column].icon_region = p_icon_region;
_changed_notify(p_column);
}
@@ -226,7 +226,7 @@ Rect2 TreeItem::get_icon_region(int p_column) const {
void TreeItem::set_icon_color(int p_column, const Color &p_icon_color) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].icon_color = p_icon_color;
+ cells.write[p_column].icon_color = p_icon_color;
_changed_notify(p_column);
}
@@ -239,7 +239,7 @@ Color TreeItem::get_icon_color(int p_column) const {
void TreeItem::set_icon_max_width(int p_column, int p_max) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].icon_max_w = p_max;
+ cells.write[p_column].icon_max_w = p_max;
_changed_notify(p_column);
}
@@ -260,7 +260,7 @@ void TreeItem::set_range(int p_column, double p_value) {
if (p_value > cells[p_column].max)
p_value = cells[p_column].max;
- cells[p_column].val = p_value;
+ cells.write[p_column].val = p_value;
_changed_notify(p_column);
}
@@ -278,10 +278,10 @@ bool TreeItem::is_range_exponential(int p_column) const {
void TreeItem::set_range_config(int p_column, double p_min, double p_max, double p_step, bool p_exp) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].min = p_min;
- cells[p_column].max = p_max;
- cells[p_column].step = p_step;
- cells[p_column].expr = p_exp;
+ cells.write[p_column].min = p_min;
+ cells.write[p_column].max = p_max;
+ cells.write[p_column].step = p_step;
+ cells.write[p_column].expr = p_exp;
_changed_notify(p_column);
}
@@ -296,7 +296,7 @@ void TreeItem::get_range_config(int p_column, double &r_min, double &r_max, doub
void TreeItem::set_metadata(int p_column, const Variant &p_meta) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].meta = p_meta;
+ cells.write[p_column].meta = p_meta;
}
Variant TreeItem::get_metadata(int p_column) const {
@@ -311,8 +311,8 @@ void TreeItem::set_custom_draw(int p_column, Object *p_object, const StringName
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_NULL(p_object);
- cells[p_column].custom_draw_obj = p_object->get_instance_id();
- cells[p_column].custom_draw_callback = p_callback;
+ cells.write[p_column].custom_draw_obj = p_object->get_instance_id();
+ cells.write[p_column].custom_draw_callback = p_callback;
}
void TreeItem::set_collapsed(bool p_collapsed) {
@@ -467,7 +467,7 @@ void TreeItem::remove_child(TreeItem *p_item) {
void TreeItem::set_selectable(int p_column, bool p_selectable) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].selectable = p_selectable;
+ cells.write[p_column].selectable = p_selectable;
}
bool TreeItem::is_selectable(int p_column) const {
@@ -517,7 +517,7 @@ void TreeItem::add_button(int p_column, const Ref<Texture> &p_button, int p_id,
button.id = p_id;
button.disabled = p_disabled;
button.tooltip = p_tooltip;
- cells[p_column].buttons.push_back(button);
+ cells.write[p_column].buttons.push_back(button);
_changed_notify(p_column);
}
@@ -540,7 +540,7 @@ void TreeItem::erase_button(int p_column, int p_idx) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
- cells[p_column].buttons.remove(p_idx);
+ cells.write[p_column].buttons.remove(p_idx);
_changed_notify(p_column);
}
@@ -568,7 +568,7 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture> &p_button)
ERR_FAIL_COND(p_button.is_null());
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
- cells[p_column].buttons[p_idx].texture = p_button;
+ cells.write[p_column].buttons.write[p_idx].texture = p_button;
_changed_notify(p_column);
}
@@ -576,14 +576,14 @@ void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
- cells[p_column].buttons[p_idx].color = p_color;
+ cells.write[p_column].buttons.write[p_idx].color = p_color;
_changed_notify(p_column);
}
void TreeItem::set_editable(int p_column, bool p_editable) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].editable = p_editable;
+ cells.write[p_column].editable = p_editable;
_changed_notify(p_column);
}
@@ -596,8 +596,8 @@ bool TreeItem::is_editable(int p_column) {
void TreeItem::set_custom_color(int p_column, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].custom_color = true;
- cells[p_column].color = p_color;
+ cells.write[p_column].custom_color = true;
+ cells.write[p_column].color = p_color;
_changed_notify(p_column);
}
Color TreeItem::get_custom_color(int p_column) const {
@@ -610,15 +610,15 @@ Color TreeItem::get_custom_color(int p_column) const {
void TreeItem::clear_custom_color(int p_column) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].custom_color = false;
- cells[p_column].color = Color();
+ cells.write[p_column].custom_color = false;
+ cells.write[p_column].color = Color();
_changed_notify(p_column);
}
void TreeItem::set_tooltip(int p_column, const String &p_tooltip) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].tooltip = p_tooltip;
+ cells.write[p_column].tooltip = p_tooltip;
}
String TreeItem::get_tooltip(int p_column) const {
@@ -630,17 +630,17 @@ String TreeItem::get_tooltip(int p_column) const {
void TreeItem::set_custom_bg_color(int p_column, const Color &p_color, bool p_bg_outline) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].custom_bg_color = true;
- cells[p_column].custom_bg_outline = p_bg_outline;
- cells[p_column].bg_color = p_color;
+ cells.write[p_column].custom_bg_color = true;
+ cells.write[p_column].custom_bg_outline = p_bg_outline;
+ cells.write[p_column].bg_color = p_color;
_changed_notify(p_column);
}
void TreeItem::clear_custom_bg_color(int p_column) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].custom_bg_color = false;
- cells[p_column].bg_color = Color();
+ cells.write[p_column].custom_bg_color = false;
+ cells.write[p_column].bg_color = Color();
_changed_notify(p_column);
}
@@ -655,7 +655,7 @@ Color TreeItem::get_custom_bg_color(int p_column) const {
void TreeItem::set_custom_as_button(int p_column, bool p_button) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].custom_button = p_button;
+ cells.write[p_column].custom_button = p_button;
}
bool TreeItem::is_custom_set_as_button(int p_column) const {
@@ -666,7 +666,7 @@ bool TreeItem::is_custom_set_as_button(int p_column) const {
void TreeItem::set_text_align(int p_column, TextAlign p_align) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].text_align = p_align;
+ cells.write[p_column].text_align = p_align;
_changed_notify(p_column);
}
@@ -678,7 +678,7 @@ TreeItem::TextAlign TreeItem::get_text_align(int p_column) const {
void TreeItem::set_expand_right(int p_column, bool p_enable) {
ERR_FAIL_INDEX(p_column, cells.size());
- cells[p_column].expand_right = p_enable;
+ cells.write[p_column].expand_right = p_enable;
_changed_notify(p_column);
}
@@ -1419,7 +1419,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
while (c) {
- if (cache.draw_relationship_lines == 1) {
+ if (cache.draw_relationship_lines == 1 && (c->get_parent() != root || c->get_parent() == root && !hide_root)) {
int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin);
Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs;
@@ -1486,7 +1486,7 @@ int Tree::_count_selected_items(TreeItem *p_from) const {
}
void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) {
- TreeItem::Cell &selected_cell = p_selected->cells[p_col];
+ TreeItem::Cell &selected_cell = p_selected->cells.write[p_col];
bool switched = false;
if (r_in_range && !*r_in_range && (p_current == p_selected || p_current == p_prev)) {
@@ -1498,7 +1498,7 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c
for (int i = 0; i < columns.size(); i++) {
- TreeItem::Cell &c = p_current->cells[i];
+ TreeItem::Cell &c = p_current->cells.write[i];
if (!c.selectable)
continue;
@@ -1689,7 +1689,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
return -1; //collapse/uncollapse because nothing can be done with item
}
- TreeItem::Cell &c = p_item->cells[col];
+ const TreeItem::Cell &c = p_item->cells[col];
bool already_selected = c.selected;
bool already_cursor = (p_item == selected_item) && col == selected_col;
@@ -1990,7 +1990,7 @@ void Tree::text_editor_enter(String p_text) {
if (popup_edited_item_col < 0 || popup_edited_item_col > columns.size())
return;
- TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col];
+ TreeItem::Cell &c = popup_edited_item->cells.write[popup_edited_item_col];
switch (c.mode) {
case TreeItem::CELL_MODE_STRING: {
@@ -2041,7 +2041,7 @@ void Tree::value_editor_changed(double p_value) {
return;
}
- TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col];
+ TreeItem::Cell &c = popup_edited_item->cells.write[popup_edited_item_col];
c.val = p_value;
item_edited(popup_edited_item_col, popup_edited_item);
update();
@@ -2055,7 +2055,7 @@ void Tree::popup_select(int p_option) {
if (popup_edited_item_col < 0 || popup_edited_item_col > columns.size())
return;
- popup_edited_item->cells[popup_edited_item_col].val = p_option;
+ popup_edited_item->cells.write[popup_edited_item_col].val = p_option;
//popup_edited_item->edited_signal.call( popup_edited_item_col );
update();
item_edited(popup_edited_item_col, popup_edited_item);
@@ -2426,14 +2426,23 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
int col, h, section;
TreeItem *it = _find_item_at_pos(root, mpos, col, h, section);
- if ((drop_mode_flags && it != drop_mode_over) || section != drop_mode_section) {
- drop_mode_over = it;
- drop_mode_section = section;
- update();
+ if (drop_mode_flags) {
+ if (it != drop_mode_over) {
+ drop_mode_over = it;
+ update();
+ }
+ if (it && section != drop_mode_section) {
+ drop_mode_section = section;
+ update();
+ }
}
- if (it != cache.hover_item || col != cache.hover_cell) {
+ if (it != cache.hover_item) {
cache.hover_item = it;
+ update();
+ }
+
+ if (it && col != cache.hover_cell) {
cache.hover_cell = col;
update();
}
@@ -2458,7 +2467,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
} else {
- TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col];
+ const TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col];
float diff_y = -mm->get_relative().y;
diff_y = Math::pow(ABS(diff_y), 1.8f) * SGN(diff_y);
diff_y *= 0.1;
@@ -2672,7 +2681,7 @@ bool Tree::edit_selected() {
popup_edited_item = s;
popup_edited_item_col = col;
- TreeItem::Cell &c = s->cells[col];
+ const TreeItem::Cell &c = s->cells[col];
if (c.mode == TreeItem::CELL_MODE_CHECK) {
@@ -3063,7 +3072,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
if (!p_item->cells[p_column].selectable)
return;
- p_item->cells[p_column].selected = true;
+ p_item->cells.write[p_column].selected = true;
//emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select
selected_col = p_column;
@@ -3077,7 +3086,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
void Tree::item_deselected(int p_column, TreeItem *p_item) {
if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) {
- p_item->cells[p_column].selected = false;
+ p_item->cells.write[p_column].selected = false;
}
update();
}
@@ -3158,14 +3167,14 @@ void Tree::set_column_min_width(int p_column, int p_min_width) {
if (p_min_width < 1)
return;
- columns[p_column].min_width = p_min_width;
+ columns.write[p_column].min_width = p_min_width;
update();
}
void Tree::set_column_expand(int p_column, bool p_expand) {
ERR_FAIL_INDEX(p_column, columns.size());
- columns[p_column].expand = p_expand;
+ columns.write[p_column].expand = p_expand;
update();
}
@@ -3413,7 +3422,7 @@ bool Tree::are_column_titles_visible() const {
void Tree::set_column_title(int p_column, const String &p_title) {
ERR_FAIL_INDEX(p_column, columns.size());
- columns[p_column].title = p_title;
+ columns.write[p_column].title = p_title;
update();
}
@@ -3659,7 +3668,7 @@ String Tree::get_tooltip(const Point2 &p_pos) const {
if (it) {
- TreeItem::Cell &c = it->cells[col];
+ const TreeItem::Cell &c = it->cells[col];
int col_width = get_column_width(col);
for (int j = c.buttons.size() - 1; j >= 0; j--) {
Ref<Texture> b = c.buttons[j].texture;
@@ -3822,16 +3831,16 @@ void Tree::_bind_methods() {
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")));
+ ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected")));
ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::VECTOR2, "position")));
ADD_SIGNAL(MethodInfo("empty_tree_rmb_selected", PropertyInfo(Variant::VECTOR2, "position")));
ADD_SIGNAL(MethodInfo("item_edited"));
ADD_SIGNAL(MethodInfo("item_rmb_edited"));
ADD_SIGNAL(MethodInfo("item_custom_button_pressed"));
ADD_SIGNAL(MethodInfo("item_double_clicked"));
- ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item")));
+ ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem")));
//ADD_SIGNAL( MethodInfo("item_doubleclicked" ) );
- ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id")));
+ ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked")));
ADD_SIGNAL(MethodInfo("item_activated"));
ADD_SIGNAL(MethodInfo("column_title_pressed", PropertyInfo(Variant::INT, "column")));
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 8414210952..a2e890e7a7 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -248,12 +248,10 @@ void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport);
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_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", 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");
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index ae21775c55..4750e05633 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -30,8 +30,6 @@
#include "http_request.h"
-#include "version.h"
-
void HTTPRequest::_redirect_request(const String &p_new_url) {
}
@@ -106,28 +104,10 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
validate_ssl = p_ssl_validate_domain;
- bool has_user_agent = false;
- bool has_accept = false;
headers = p_custom_headers;
request_data = p_request_data;
- for (int i = 0; i < headers.size(); i++) {
-
- if (headers[i].findn("user-agent:") == 0)
- has_user_agent = true;
- if (headers[i].findn("Accept:") == 0)
- has_accept = true;
- }
-
- if (!has_user_agent) {
- headers.push_back("User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")");
- }
-
- if (!has_accept) {
- headers.push_back("Accept: */*");
- }
-
requesting = true;
if (use_threads) {
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 4dc7b03685..e30f58e012 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -240,7 +240,7 @@ void Node::_propagate_enter_tree() {
void Node::_propagate_exit_tree() {
-//block while removing children
+ //block while removing children
#ifdef DEBUG_ENABLED
@@ -725,6 +725,17 @@ const Map<StringName, MultiplayerAPI::RPCMode>::Element *Node::get_node_rset_mod
return data.rpc_properties.find(p_property);
}
+bool Node::can_process_notification(int p_what) const {
+ switch (p_what) {
+ case NOTIFICATION_PHYSICS_PROCESS: return data.physics_process;
+ case NOTIFICATION_PROCESS: return data.idle_process;
+ case NOTIFICATION_INTERNAL_PROCESS: return data.idle_process_internal;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: return data.physics_process_internal;
+ }
+
+ return true;
+}
+
bool Node::can_process() const {
ERR_FAIL_COND_V(!is_inside_tree(), false);
@@ -809,6 +820,22 @@ bool Node::is_processing_internal() const {
return data.idle_process_internal;
}
+void Node::set_process_priority(int p_priority) {
+ data.process_priority = p_priority;
+
+ if (is_processing())
+ data.tree->make_group_changed("idle_process");
+
+ if (is_processing_internal())
+ data.tree->make_group_changed("idle_process_internal");
+
+ if (is_physics_processing())
+ data.tree->make_group_changed("physics_process");
+
+ if (is_physics_processing_internal())
+ data.tree->make_group_changed("physics_process_internal");
+}
+
void Node::set_process_input(bool p_enable) {
if (p_enable == data.input)
@@ -1895,7 +1922,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
// Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later
// 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)
+ if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this && descendant->data.owner != descendant->get_parent())
hidden_roots.push_back(descendant);
continue;
}
@@ -1934,8 +1961,9 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) {
Resource *res = Object::cast_to<Resource>(value);
- if (res) // Duplicate only if it's a resource
+ if (res) { // Duplicate only if it's a resource
current_node->set(name, res->duplicate());
+ }
} else {
@@ -2054,9 +2082,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
} else {
Object *obj = ClassDB::instance(get_class());
- if (!obj) {
- print_line("could not duplicate: " + String(get_class()));
- }
+ ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class()));
ERR_FAIL_COND(!obj);
node = Object::cast_to<Node>(obj);
if (!node)
@@ -2151,9 +2177,7 @@ Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const {
Node *node = NULL;
Object *obj = ClassDB::instance(get_class());
- if (!obj) {
- print_line("could not duplicate: " + String(get_class()));
- }
+ ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class()));
ERR_FAIL_COND_V(!obj, NULL);
node = Object::cast_to<Node>(obj);
if (!node)
@@ -2444,7 +2468,7 @@ static void _Node_debug_sn(Object *p_obj) {
path = n->get_name();
else
path = String(p->get_name()) + "/" + p->get_path_to(n);
- print_line(itos(p_obj->get_instance_id()) + "- Stray Node: " + path + " (Type: " + n->get_class() + ")");
+ print_line(itos(p_obj->get_instance_id()) + " - Stray Node: " + path + " (Type: " + n->get_class() + ")");
}
void Node::_print_stray_nodes() {
@@ -2527,6 +2551,9 @@ void Node::clear_internal_tree_resource_paths() {
String Node::get_configuration_warning() const {
+ if (get_script_instance() && get_script_instance()->has_method("_get_configuration_warning")) {
+ return get_script_instance()->call("_get_configuration_warning");
+ }
return String();
}
@@ -2607,6 +2634,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_physics_processing"), &Node::is_physics_processing);
ClassDB::bind_method(D_METHOD("get_process_delta_time"), &Node::get_process_delta_time);
ClassDB::bind_method(D_METHOD("set_process", "enable"), &Node::set_process);
+ ClassDB::bind_method(D_METHOD("set_process_priority", "priority"), &Node::set_process_priority);
ClassDB::bind_method(D_METHOD("is_processing"), &Node::is_processing);
ClassDB::bind_method(D_METHOD("set_process_input", "enable"), &Node::set_process_input);
ClassDB::bind_method(D_METHOD("is_processing_input"), &Node::is_processing_input);
@@ -2734,6 +2762,7 @@ void Node::_bind_methods() {
BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey")));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning"));
//ClassDB::bind_method(D_METHOD("get_child",&Node::get_child,PH("index")));
//ClassDB::bind_method(D_METHOD("get_node",&Node::get_node,PH("path")));
@@ -2758,6 +2787,7 @@ Node::Node() {
data.tree = NULL;
data.physics_process = false;
data.idle_process = false;
+ data.process_priority = 0;
data.physics_process_internal = false;
data.idle_process_internal = false;
data.inside_tree = false;
diff --git a/scene/main/node.h b/scene/main/node.h
index 341349de79..f3422618ce 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -70,6 +70,11 @@ public:
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->is_greater_than(p_a); }
};
+ struct ComparatorWithPriority {
+
+ bool operator()(const Node *p_a, const Node *p_b) const { return p_b->data.process_priority == p_a->data.process_priority ? p_b->is_greater_than(p_a) : p_b->data.process_priority > p_a->data.process_priority; }
+ };
+
private:
struct GroupData {
@@ -118,6 +123,7 @@ private:
//should move all the stuff below to bits
bool physics_process;
bool idle_process;
+ int process_priority;
bool physics_process_internal;
bool idle_process_internal;
@@ -319,6 +325,8 @@ public:
void set_process_internal(bool p_idle_process_internal);
bool is_processing_internal() const;
+ void set_process_priority(int p_priority);
+
void set_process_input(bool p_enable);
bool is_processing_input() const;
@@ -355,6 +363,7 @@ public:
void set_pause_mode(PauseMode p_mode);
PauseMode get_pause_mode() const;
bool can_process() const;
+ bool can_process_notification(int p_what) const;
void request_ready();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 8d6e57b335..11268cc5c6 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -132,6 +132,12 @@ void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) {
group_map.erase(E);
}
+void SceneTree::make_group_changed(const StringName &p_group) {
+ Map<StringName, Group>::Element *E = group_map.find(p_group);
+ if (E)
+ E->get().changed = true;
+}
+
void SceneTree::flush_transform_notifications() {
SelfList<Node> *n = xform_change_list.first();
@@ -165,18 +171,23 @@ void SceneTree::_flush_ugc() {
ugc_locked = false;
}
-void SceneTree::_update_group_order(Group &g) {
+void SceneTree::_update_group_order(Group &g, bool p_use_priority) {
if (!g.changed)
return;
if (g.nodes.empty())
return;
- Node **nodes = &g.nodes[0];
+ Node **nodes = g.nodes.ptrw();
int node_count = g.nodes.size();
- SortArray<Node *, Node::Comparator> node_sort;
- node_sort.sort(nodes, node_count);
+ if (p_use_priority) {
+ SortArray<Node *, Node::ComparatorWithPriority> node_sort;
+ node_sort.sort(nodes, node_count);
+ } else {
+ SortArray<Node *, Node::Comparator> node_sort;
+ node_sort.sort(nodes, node_count);
+ }
g.changed = false;
}
@@ -216,7 +227,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = &nodes_copy[0];
+ Node **nodes = nodes_copy.ptrw();
int node_count = nodes_copy.size();
call_lock++;
@@ -271,7 +282,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = &nodes_copy[0];
+ Node **nodes = nodes_copy.ptrw();
int node_count = nodes_copy.size();
call_lock++;
@@ -320,7 +331,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = &nodes_copy[0];
+ Node **nodes = nodes_copy.ptrw();
int node_count = nodes_copy.size();
call_lock++;
@@ -498,7 +509,8 @@ bool SceneTree::idle(float p_time) {
_notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS);
_notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS);
- Size2 win_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height);
+ Size2 win_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
+
if (win_size != last_screen_size) {
last_screen_size = win_size;
@@ -656,6 +668,11 @@ void SceneTree::_notification(int p_notification) {
#endif
} break;
+ case NOTIFICATION_CRASH: {
+
+ get_root()->propagate_notification(p_notification);
+ } break;
+
default:
break;
};
@@ -878,7 +895,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
Vector<Node *> nodes_copy = g.nodes;
int node_count = nodes_copy.size();
- Node **nodes = &nodes_copy[0];
+ Node **nodes = nodes_copy.ptrw();
Variant arg = p_input;
const Variant *v[1] = { &arg };
@@ -915,14 +932,14 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (g.nodes.empty())
return;
- _update_group_order(g);
+ _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
//copy, so copy on write happens in case something is removed from process while being called
//performance is not lost because only if something is added/removed the vector is copied.
Vector<Node *> nodes_copy = g.nodes;
int node_count = nodes_copy.size();
- Node **nodes = &nodes_copy[0];
+ Node **nodes = nodes_copy.ptrw();
call_lock++;
@@ -934,6 +951,8 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
if (!n->can_process())
continue;
+ if (!n->can_process_notification(p_notification))
+ continue;
n->notification(p_notification);
//ERR_FAIL_COND(node_count != g.nodes.size());
@@ -1112,7 +1131,7 @@ void SceneTree::_update_root_rect() {
}
//actual screen video mode
- Size2 video_mode = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height);
+ Size2 video_mode = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
Size2 desired_res = stretch_min;
Size2 viewport_size;
@@ -1176,8 +1195,6 @@ void SceneTree::_update_root_rect() {
VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0);
}
- //print_line("VP SIZE: "+viewport_size+" OFFSET: "+offset+" = "+(offset*2+viewport_size));
- //print_line("SS: "+video_mode);
switch (stretch_mode) {
case STRETCH_MODE_2D: {
@@ -1845,10 +1862,10 @@ void SceneTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled");
ADD_SIGNAL(MethodInfo("tree_changed"));
- ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node")));
- ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node")));
+ ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
+ ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("screen_resized"));
- ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node")));
+ ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("idle_frame"));
ADD_SIGNAL(MethodInfo("physics_frame"));
@@ -2004,7 +2021,7 @@ SceneTree::SceneTree() {
stretch_aspect = STRETCH_ASPECT_IGNORE;
stretch_shrink = 1;
- last_screen_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height);
+ last_screen_size = Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
_update_root_rect();
if (ScriptDebugger::get_singleton()) {
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index aa8d78b1e1..11201097d4 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -161,7 +161,7 @@ private:
bool ugc_locked;
void _flush_ugc();
- _FORCE_INLINE_ void _update_group_order(Group &g);
+ _FORCE_INLINE_ void _update_group_order(Group &g, bool p_use_priority = false);
void _update_listener();
Array _get_nodes_in_group(const StringName &p_group);
@@ -204,6 +204,7 @@ private:
Group *add_to_group(const StringName &p_group, Node *p_node);
void remove_from_group(const StringName &p_group, Node *p_node);
+ void make_group_changed(const StringName &p_group);
void _notify_group_pause(const StringName &p_group, int p_notification);
void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 1236aea2dd..d1b3eb9d9a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -41,7 +41,10 @@
#include "scene/3d/spatial.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/popup_menu.h"
#include "scene/main/timer.h"
#include "scene/resources/mesh.h"
#include "scene/scene_string_names.h"
@@ -144,7 +147,7 @@ void ViewportTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene);
ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path"), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport"), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
}
ViewportTexture::ViewportTexture() {
@@ -166,9 +169,9 @@ ViewportTexture::~ViewportTexture() {
/////////////////////////////////////
-class TooltipPanel : public Panel {
+class TooltipPanel : public PanelContainer {
- GDCLASS(TooltipPanel, Panel)
+ GDCLASS(TooltipPanel, PanelContainer)
public:
TooltipPanel(){};
};
@@ -182,6 +185,7 @@ public:
Viewport::GUI::GUI() {
+ dragging = false;
mouse_focus = NULL;
mouse_click_grabber = NULL;
mouse_focus_button = -1;
@@ -441,7 +445,7 @@ void Viewport::_notification(int p_what) {
Vector2 point = get_canvas_transform().affine_inverse().xform(pos);
Physics2DDirectSpaceState::ShapeResult res[64];
- int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true);
+ int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
for (int i = 0; i < rc; i++) {
if (res[i].collider_id && res[i].collider) {
@@ -524,7 +528,7 @@ void Viewport::_notification(int p_what) {
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
- bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true);
+ bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider = 0;
if (col) {
@@ -560,7 +564,7 @@ void Viewport::_notification(int p_what) {
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
- bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true);
+ bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider = 0;
if (col) {
CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
@@ -626,7 +630,7 @@ Rect2 Viewport::get_visible_rect() const {
if (size == Size2()) {
- r = Rect2(Point2(), Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height));
+ r = Rect2(Point2(), Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height));
} else {
r = Rect2(Point2(), size);
@@ -1305,10 +1309,11 @@ void Viewport::_gui_cancel_tooltip() {
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
gui.tooltip_popup = NULL;
+ gui.tooltip_label = NULL;
}
}
-String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos) {
+String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) {
Vector2 pos = p_pos;
String tooltip;
@@ -1317,6 +1322,10 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos) {
tooltip = p_control->get_tooltip(pos);
+ if (r_which) {
+ *r_which = p_control;
+ }
+
if (tooltip != String())
break;
pos = p_control->get_transform().xform(pos);
@@ -1338,41 +1347,49 @@ void Viewport::_gui_show_tooltip() {
return;
}
- String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos));
+ Control *which = NULL;
+ String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
if (tooltip.length() == 0)
return; // bye
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
gui.tooltip_popup = NULL;
+ gui.tooltip_label = NULL;
}
- if (!gui.tooltip) {
+ if (!which) {
return;
}
- Control *rp = gui.tooltip->get_root_parent_control();
+ Control *rp = which; //->get_root_parent_control();
if (!rp)
return;
- gui.tooltip_popup = memnew(TooltipPanel);
+ gui.tooltip_popup = which->make_custom_tooltip(tooltip);
+
+ if (!gui.tooltip_popup) {
+ gui.tooltip_popup = memnew(TooltipPanel);
+
+ gui.tooltip_label = memnew(TooltipLabel);
+ gui.tooltip_popup->add_child(gui.tooltip_label);
+
+ Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel");
+
+ gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT));
+ 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.strip_edges());
+ }
rp->add_child(gui.tooltip_popup);
gui.tooltip_popup->force_parent_owned();
- gui.tooltip_label = memnew(TooltipLabel);
- gui.tooltip_popup->add_child(gui.tooltip_label);
gui.tooltip_popup->set_as_toplevel(true);
- gui.tooltip_popup->hide();
-
- Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel");
+ //gui.tooltip_popup->hide();
- gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT));
- 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.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();
+ Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_popup->get_minimum_size());
+ Rect2 vr = gui.tooltip_popup->get_viewport_rect();
if (r.size.x + r.position.x > vr.size.x)
r.position.x = vr.size.x - r.size.x;
else if (r.position.x < 0)
@@ -1404,6 +1421,8 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
mb->get_button_index() == BUTTON_WHEEL_UP ||
mb->get_button_index() == BUTTON_WHEEL_LEFT ||
mb->get_button_index() == BUTTON_WHEEL_RIGHT));
+ Ref<InputEventPanGesture> pn = p_input;
+ cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
bool ismouse = ev.is_valid() || Object::cast_to<InputEventMouseMotion>(*p_input) != NULL;
@@ -1488,12 +1507,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
if (Object::cast_to<Viewport>(p_node))
return NULL;
- Control *c = Object::cast_to<Control>(p_node);
-
- if (c) {
- //print_line("at "+String(c->get_path())+" POS "+c->get_position()+" bt "+p_xform);
- }
-
//subwindows first!!
if (!p_node->is_visible()) {
@@ -1506,6 +1519,8 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
if (matrix.basis_determinant() == 0.0f)
return NULL;
+ Control *c = Object::cast_to<Control>(p_node);
+
if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
@@ -1636,7 +1651,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
*/
gui.mouse_focus = _gui_find_control(pos);
- //print_line("has mf "+itos(gui.mouse_focus!=NULL));
gui.mouse_focus_button = mb->get_button_index();
if (!gui.mouse_focus) {
@@ -1665,11 +1679,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
arr.push_back(gui.mouse_focus->get_class());
ScriptDebugger::get_singleton()->send_message("click_ctrl", arr);
}
-
-/*if (bool(GLOBAL_DEF("debug/print_clicked_control",false))) {
-
- print_line(String(gui.mouse_focus->get_path())+" - "+pos);
- }*/
#endif
if (mb->get_button_index() == BUTTON_LEFT) { //assign focus
@@ -1710,6 +1719,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
gui.drag_data = Variant();
+ gui.dragging = false;
if (gui.drag_preview) {
memdelete(gui.drag_preview);
@@ -1739,6 +1749,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
gui.drag_data = Variant();
+ gui.dragging = false;
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
}
@@ -1801,10 +1812,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *control = Object::cast_to<Control>(ci);
if (control) {
+ gui.dragging = true;
gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum);
if (gui.drag_data.get_type() != Variant::NIL) {
gui.mouse_focus = NULL;
+ } else {
+ gui.dragging = false;
}
if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
@@ -1838,8 +1852,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
Control *top = gui.modal_stack.back()->get();
+
if (over != top && !top->is_a_parent_of(over)) {
- over = NULL; //nothing can be found outside the modal stack
+
+ PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top);
+ MenuButton *popup_menu_parent = NULL;
+ MenuButton *menu_button = Object::cast_to<MenuButton>(over);
+
+ if (popup_menu)
+ popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
+
+ // If the mouse is over a menu button, this menu will open automatically
+ // if there is already a pop-up menu open at the same hierarchical level.
+ if (popup_menu_parent && menu_button &&
+ popup_menu_parent->get_icon().is_null() &&
+ menu_button->get_icon().is_null() &&
+ (popup_menu->get_parent()->get_parent()->is_a_parent_of(menu_button) ||
+ menu_button->get_parent()->is_a_parent_of(popup_menu))) {
+
+ popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE);
+ popup_menu->_modal_stack_remove();
+ popup_menu->hide();
+
+ menu_button->pressed();
+ } else {
+ over = NULL; //nothing can be found outside the modal stack
+ }
}
}
@@ -1889,13 +1927,18 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool is_tooltip_shown = false;
if (gui.tooltip_popup) {
- if (can_tooltip) {
+ if (can_tooltip && gui.tooltip) {
String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
if (tooltip.length() == 0)
_gui_cancel_tooltip();
- else if (tooltip == gui.tooltip_label->get_text())
+ else if (gui.tooltip_label) {
+ if (tooltip == gui.tooltip_label->get_text()) {
+ is_tooltip_shown = true;
+ }
+ } else if (tooltip == String(gui.tooltip_popup->call("get_tooltip_text"))) {
is_tooltip_shown = true;
+ }
} else
_gui_cancel_tooltip();
}
@@ -2215,6 +2258,7 @@ void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *
ERR_EXPLAIN("Drag data must be a value");
ERR_FAIL_COND(p_data.get_type() == Variant::NIL);
+ gui.dragging = true;
gui.drag_data = p_data;
gui.mouse_focus = NULL;
@@ -2654,6 +2698,9 @@ bool Viewport::is_snap_controls_to_pixels_enabled() const {
return snap_controls_to_pixels;
}
+bool Viewport::gui_is_dragging() const {
+ return gui.dragging;
+}
void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr);
@@ -2740,6 +2787,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
+ ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 3000398540..450f235b79 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -31,11 +31,11 @@
#ifndef VIEWPORT_H
#define VIEWPORT_H
-#include "math_2d.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
#include "scene/resources/world_2d.h"
#include "servers/visual_server.h"
+#include "transform_2d.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -255,7 +255,7 @@ private:
Control *key_focus;
Control *mouse_over;
Control *tooltip;
- Panel *tooltip_popup;
+ Control *tooltip_popup;
Label *tooltip_label;
Point2 tooltip_pos;
Point2 last_mouse_pos;
@@ -274,6 +274,7 @@ private:
bool roots_order_dirty;
List<Control *> roots;
int canvas_sort_index; //for sorting items with canvas as root
+ bool dragging;
GUI();
} gui;
@@ -312,7 +313,7 @@ private:
void _gui_remove_root_control(List<Control *>::Element *RI);
void _gui_remove_subwindow_control(List<Control *>::Element *SI);
- String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos);
+ String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL);
void _gui_cancel_tooltip();
void _gui_show_tooltip();
@@ -474,6 +475,8 @@ public:
void _subwindow_visibility_changed();
+ bool gui_is_dragging() const;
+
Viewport();
~Viewport();
};
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index e8ab7b3398..97230d422b 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -42,6 +42,7 @@
#include "scene/2d/canvas_modulate.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/collision_shape_2d.h"
+#include "scene/2d/cpu_particles_2d.h"
#include "scene/2d/joints_2d.h"
#include "scene/2d/light_2d.h"
#include "scene/2d/light_occluder_2d.h"
@@ -134,6 +135,7 @@
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape.h"
#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/cylinder_shape.h"
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/dynamic_font.h"
#include "scene/resources/dynamic_font_stb.h"
@@ -142,6 +144,7 @@
#include "scene/resources/mesh_data_tool.h"
#include "scene/resources/mesh_library.h"
#include "scene/resources/packed_scene.h"
+#include "scene/resources/particles_material.h"
#include "scene/resources/plane_shape.h"
#include "scene/resources/polygon_path_finder.h"
#include "scene/resources/primitive_meshes.h"
@@ -149,19 +152,20 @@
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/scene_format_text.h"
#include "scene/resources/segment_shape_2d.h"
-#include "scene/resources/shader_graph.h"
#include "scene/resources/shape_line_2d.h"
#include "scene/resources/sky_box.h"
#include "scene/resources/sphere_shape.h"
#include "scene/resources/surface_tool.h"
+#include "scene/resources/text_file.h"
#include "scene/resources/texture.h"
#include "scene/resources/tile_set.h"
#include "scene/resources/video_stream.h"
+#include "scene/resources/visual_shader.h"
+#include "scene/resources/visual_shader_nodes.h"
#include "scene/resources/world.h"
#include "scene/resources/world_2d.h"
#include "scene/scene_string_names.h"
-#include "scene/3d/particles.h"
#include "scene/3d/scenario_fx.h"
#include "scene/3d/spatial.h"
@@ -174,6 +178,7 @@
#include "scene/3d/camera.h"
#include "scene/3d/collision_polygon.h"
#include "scene/3d/collision_shape.h"
+#include "scene/3d/cpu_particles.h"
#include "scene/3d/gi_probe.h"
#include "scene/3d/immediate_geometry.h"
#include "scene/3d/interpolated_camera.h"
@@ -183,6 +188,7 @@
#include "scene/3d/multimesh_instance.h"
#include "scene/3d/navigation.h"
#include "scene/3d/navigation_mesh.h"
+#include "scene/3d/particles.h"
#include "scene/3d/path.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/physics_joint.h"
@@ -194,10 +200,14 @@
#include "scene/3d/remote_transform.h"
#include "scene/3d/room_instance.h"
#include "scene/3d/skeleton.h"
+#include "scene/3d/soft_body.h"
+#include "scene/3d/spring_arm.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body.h"
#include "scene/3d/visibility_notifier.h"
+#include "scene/animation/skeleton_ik.h"
#include "scene/resources/environment.h"
+#include "scene/resources/physics_material.h"
#endif
static ResourceFormatLoaderTheme *resource_loader_theme = NULL;
@@ -208,6 +218,7 @@ static ResourceFormatLoaderText *resource_loader_text = NULL;
static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL;
static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL;
+static ResourceFormatLoaderTextureLayered *resource_loader_texture_layered = NULL;
static ResourceFormatLoaderBMFont *resource_loader_bmfont = NULL;
@@ -228,6 +239,9 @@ void register_scene_types() {
resource_loader_stream_texture = memnew(ResourceFormatLoaderStreamTexture);
ResourceLoader::add_resource_format_loader(resource_loader_stream_texture);
+ resource_loader_texture_layered = memnew(ResourceFormatLoaderTextureLayered);
+ ResourceLoader::add_resource_format_loader(resource_loader_texture_layered);
+
resource_loader_theme = memnew(ResourceFormatLoaderTheme);
ResourceLoader::add_resource_format_loader(resource_loader_theme);
@@ -307,21 +321,19 @@ void register_scene_types() {
ClassDB::register_class<CenterContainer>();
ClassDB::register_class<ScrollContainer>();
ClassDB::register_class<PanelContainer>();
- ClassDB::register_virtual_class<SplitContainer>();
- ClassDB::register_class<HSplitContainer>();
- ClassDB::register_class<VSplitContainer>();
- ClassDB::register_class<GraphNode>();
- ClassDB::register_class<GraphEdit>();
OS::get_singleton()->yield(); //may take time to init
ClassDB::register_class<TextureProgress>();
ClassDB::register_class<ItemList>();
+ ClassDB::register_class<LineEdit>();
+ ClassDB::register_class<VideoPlayer>();
+
#ifndef ADVANCED_GUI_DISABLED
ClassDB::register_class<FileDialog>();
- ClassDB::register_class<LineEdit>();
+
ClassDB::register_class<PopupMenu>();
ClassDB::register_class<Tree>();
@@ -338,9 +350,13 @@ void register_scene_types() {
ClassDB::register_class<WindowDialog>();
ClassDB::register_class<AcceptDialog>();
ClassDB::register_class<ConfirmationDialog>();
- ClassDB::register_class<VideoPlayer>();
ClassDB::register_class<MarginContainer>();
ClassDB::register_class<ViewportContainer>();
+ ClassDB::register_virtual_class<SplitContainer>();
+ ClassDB::register_class<HSplitContainer>();
+ ClassDB::register_class<VSplitContainer>();
+ ClassDB::register_class<GraphNode>();
+ ClassDB::register_class<GraphEdit>();
OS::get_singleton()->yield(); //may take time to init
@@ -357,10 +373,10 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
#ifndef _3D_DISABLED
- ClassDB::register_class<BoneAttachment>();
ClassDB::register_virtual_class<VisualInstance>();
ClassDB::register_virtual_class<GeometryInstance>();
ClassDB::register_class<Camera>();
+ ClassDB::register_class<ClippedCamera>();
ClassDB::register_class<Listener>();
ClassDB::register_class<ARVRCamera>();
ClassDB::register_class<ARVRController>();
@@ -383,6 +399,7 @@ void register_scene_types() {
ClassDB::register_class<BakedLightmapData>();
ClassDB::register_class<AnimationTreePlayer>();
ClassDB::register_class<Particles>();
+ ClassDB::register_class<CPUParticles>();
ClassDB::register_class<Position3D>();
ClassDB::register_class<NavigationMeshInstance>();
ClassDB::register_class<NavigationMesh>();
@@ -398,11 +415,14 @@ void register_scene_types() {
ClassDB::register_class<AnimationNodeBlendSpace1D>();
ClassDB::register_class<AnimationNodeBlendSpace2D>();
ClassDB::register_class<AnimationNodeStateMachine>();
+ ClassDB::register_class<AnimationNodeStateMachinePlayback>();
+
ClassDB::register_class<AnimationNodeStateMachineTransition>();
ClassDB::register_class<AnimationNodeOutput>();
ClassDB::register_class<AnimationNodeOneShot>();
ClassDB::register_class<AnimationNodeAnimation>();
- ClassDB::register_class<AnimationNodeAdd>();
+ ClassDB::register_class<AnimationNodeAdd2>();
+ ClassDB::register_class<AnimationNodeAdd3>();
ClassDB::register_class<AnimationNodeBlend2>();
ClassDB::register_class<AnimationNodeBlend3>();
ClassDB::register_class<AnimationNodeTimeScale>();
@@ -417,7 +437,13 @@ void register_scene_types() {
ClassDB::register_class<RigidBody>();
ClassDB::register_class<KinematicCollision>();
ClassDB::register_class<KinematicBody>();
+ ClassDB::register_class<SpringArm>();
+
ClassDB::register_class<PhysicalBone>();
+ ClassDB::register_class<SoftBody>();
+
+ ClassDB::register_class<SkeletonIK>();
+ ClassDB::register_class<BoneAttachment>();
ClassDB::register_class<VehicleBody>();
ClassDB::register_class<VehicleWheel>();
@@ -451,12 +477,46 @@ void register_scene_types() {
AcceptDialog::set_swap_ok_cancel(GLOBAL_DEF("gui/common/swap_ok_cancel", bool(OS::get_singleton()->get_swap_ok_cancel())));
ClassDB::register_class<Shader>();
+ ClassDB::register_class<VisualShader>();
+ ClassDB::register_virtual_class<VisualShaderNode>();
+ ClassDB::register_class<VisualShaderNodeInput>();
+ ClassDB::register_virtual_class<VisualShaderNodeOutput>();
+ ClassDB::register_class<VisualShaderNodeScalarConstant>();
+ ClassDB::register_class<VisualShaderNodeColorConstant>();
+ ClassDB::register_class<VisualShaderNodeVec3Constant>();
+ ClassDB::register_class<VisualShaderNodeTransformConstant>();
+ ClassDB::register_class<VisualShaderNodeScalarOp>();
+ ClassDB::register_class<VisualShaderNodeVectorOp>();
+ ClassDB::register_class<VisualShaderNodeColorOp>();
+ ClassDB::register_class<VisualShaderNodeTransformMult>();
+ ClassDB::register_class<VisualShaderNodeTransformVecMult>();
+ ClassDB::register_class<VisualShaderNodeScalarFunc>();
+ ClassDB::register_class<VisualShaderNodeVectorFunc>();
+ ClassDB::register_class<VisualShaderNodeDotProduct>();
+ ClassDB::register_class<VisualShaderNodeVectorLen>();
+ ClassDB::register_class<VisualShaderNodeScalarInterp>();
+ ClassDB::register_class<VisualShaderNodeVectorInterp>();
+ ClassDB::register_class<VisualShaderNodeVectorCompose>();
+ ClassDB::register_class<VisualShaderNodeTransformCompose>();
+ ClassDB::register_class<VisualShaderNodeVectorDecompose>();
+ ClassDB::register_class<VisualShaderNodeTransformDecompose>();
+ ClassDB::register_class<VisualShaderNodeTexture>();
+ ClassDB::register_class<VisualShaderNodeCubeMap>();
+ ClassDB::register_virtual_class<VisualShaderNodeUniform>();
+ ClassDB::register_class<VisualShaderNodeScalarUniform>();
+ ClassDB::register_class<VisualShaderNodeColorUniform>();
+ ClassDB::register_class<VisualShaderNodeVec3Uniform>();
+ ClassDB::register_class<VisualShaderNodeTransformUniform>();
+ ClassDB::register_class<VisualShaderNodeTextureUniform>();
+ ClassDB::register_class<VisualShaderNodeCubeMapUniform>();
+
ClassDB::register_class<ShaderMaterial>();
ClassDB::register_virtual_class<CanvasItem>();
ClassDB::register_class<CanvasItemMaterial>();
SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes);
CanvasItemMaterial::init_shaders();
ClassDB::register_class<Node2D>();
+ ClassDB::register_class<CPUParticles2D>();
ClassDB::register_class<Particles2D>();
//ClassDB::register_class<ParticleAttractor2D>();
ClassDB::register_class<Sprite>();
@@ -506,6 +566,9 @@ void register_scene_types() {
/* REGISTER RESOURCES */
ClassDB::register_virtual_class<Shader>();
+ ClassDB::register_class<ParticlesMaterial>();
+ SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
+ ParticlesMaterial::init_shaders();
#ifndef _3D_DISABLED
ClassDB::register_virtual_class<Mesh>();
@@ -523,10 +586,6 @@ void register_scene_types() {
SceneTree::add_idle_callback(SpatialMaterial::flush_changes);
SpatialMaterial::init_shaders();
- ClassDB::register_class<ParticlesMaterial>();
- SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
- ParticlesMaterial::init_shaders();
-
ClassDB::register_class<MultiMesh>();
ClassDB::register_class<MeshLibrary>();
@@ -537,6 +596,7 @@ void register_scene_types() {
ClassDB::register_class<SphereShape>();
ClassDB::register_class<BoxShape>();
ClassDB::register_class<CapsuleShape>();
+ ClassDB::register_class<CylinderShape>();
ClassDB::register_class<PlaneShape>();
ClassDB::register_class<ConvexPolygonShape>();
ClassDB::register_class<ConcavePolygonShape>();
@@ -547,6 +607,8 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
ClassDB::register_class<SpatialVelocityTracker>();
+
+ ClassDB::register_class<PhysicsMaterial>();
#endif
ClassDB::register_class<World>();
ClassDB::register_class<Environment>();
@@ -562,12 +624,18 @@ void register_scene_types() {
ClassDB::register_class<CurveTexture>();
ClassDB::register_class<GradientTexture>();
ClassDB::register_class<ProxyTexture>();
+ ClassDB::register_class<AnimatedTexture>();
ClassDB::register_class<CubeMap>();
+ ClassDB::register_virtual_class<TextureLayered>();
+ ClassDB::register_class<Texture3D>();
+ ClassDB::register_class<TextureArray>();
ClassDB::register_class<Animation>();
ClassDB::register_virtual_class<Font>();
ClassDB::register_class<BitmapFont>();
ClassDB::register_class<Curve>();
+ ClassDB::register_class<TextFile>();
+
ClassDB::register_class<DynamicFontData>();
ClassDB::register_class<DynamicFont>();
@@ -674,6 +742,7 @@ void unregister_scene_types() {
memdelete(resource_loader_dynamic_font);
memdelete(resource_loader_stream_texture);
+ memdelete(resource_loader_texture_layered);
memdelete(resource_loader_theme);
DynamicFont::finish_dynamic_fonts();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index fe4d687c23..58e6db3f5e 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -100,7 +100,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < (vcount / 12); i++) {
- TKey<TransformKey> &tk = tt->transforms[i];
+ TKey<TransformKey> &tk = tt->transforms.write[i];
const float *ofs = &r[i * 12];
tk.time = ofs[0];
tk.transition = ofs[1];
@@ -134,8 +134,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
int um = d["update"];
if (um < 0)
um = 0;
- else if (um > 2)
- um = 2;
+ else if (um > 3)
+ um = 3;
vt->update_mode = UpdateMode(um);
}
@@ -154,8 +154,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < valcount; i++) {
- vt->values[i].time = rt[i];
- vt->values[i].value = values[i];
+ vt->values.write[i].time = rt[i];
+ vt->values.write[i].value = values[i];
}
if (d.has("transitions")) {
@@ -167,7 +167,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < valcount; i++) {
- vt->values[i].transition = rtr[i];
+ vt->values.write[i].transition = rtr[i];
}
}
}
@@ -235,13 +235,13 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
for (int i = 0; i < valcount; i++) {
- bt->values[i].time = rt[i];
- bt->values[i].transition = 0; //unused in bezier
- bt->values[i].value.value = rv[i * 5 + 0];
- bt->values[i].value.in_handle.x = rv[i * 5 + 1];
- bt->values[i].value.in_handle.y = rv[i * 5 + 2];
- bt->values[i].value.out_handle.x = rv[i * 5 + 3];
- bt->values[i].value.out_handle.y = rv[i * 5 + 4];
+ bt->values.write[i].time = rt[i];
+ bt->values.write[i].transition = 0; //unused in bezier
+ bt->values.write[i].value.value = rv[i * 5 + 0];
+ bt->values.write[i].value.in_handle.x = rv[i * 5 + 1];
+ bt->values.write[i].value.in_handle.y = rv[i * 5 + 2];
+ bt->values.write[i].value.out_handle.x = rv[i * 5 + 3];
+ bt->values.write[i].value.out_handle.y = rv[i * 5 + 4];
}
}
@@ -313,7 +313,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
TKey<StringName> ak;
ak.time = rt[i];
ak.value = rc[i];
- an->values[i] = ak;
+ an->values.write[i] = ak;
}
}
@@ -822,7 +822,7 @@ int Animation::_insert(float p_time, T &p_keys, const V &p_value) {
} else if (p_keys[idx - 1].time == p_time) {
// condition for replacing.
- p_keys[idx - 1] = p_value;
+ p_keys.write[idx - 1] = p_value;
return idx - 1;
}
@@ -1349,18 +1349,18 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
ERR_FAIL_INDEX(p_key_idx, tt->transforms.size());
Dictionary d = p_value;
if (d.has("location"))
- tt->transforms[p_key_idx].value.loc = d["location"];
+ tt->transforms.write[p_key_idx].value.loc = d["location"];
if (d.has("rotation"))
- tt->transforms[p_key_idx].value.rot = d["rotation"];
+ tt->transforms.write[p_key_idx].value.rot = d["rotation"];
if (d.has("scale"))
- tt->transforms[p_key_idx].value.scale = d["scale"];
+ tt->transforms.write[p_key_idx].value.scale = d["scale"];
} break;
case TYPE_VALUE: {
ValueTrack *vt = static_cast<ValueTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, vt->values.size());
- vt->values[p_key_idx].value = p_value;
+ vt->values.write[p_key_idx].value = p_value;
} break;
case TYPE_METHOD: {
@@ -1369,9 +1369,9 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
ERR_FAIL_INDEX(p_key_idx, mt->methods.size());
Dictionary d = p_value;
if (d.has("method"))
- mt->methods[p_key_idx].method = d["method"];
+ mt->methods.write[p_key_idx].method = d["method"];
if (d.has("args"))
- mt->methods[p_key_idx].params = d["args"];
+ mt->methods.write[p_key_idx].params = d["args"];
} break;
case TYPE_BEZIER: {
@@ -1381,11 +1381,11 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
Array arr = p_value;
ERR_FAIL_COND(arr.size() != 5);
- bt->values[p_key_idx].value.value = arr[0];
- bt->values[p_key_idx].value.in_handle.x = arr[1];
- bt->values[p_key_idx].value.in_handle.y = arr[2];
- bt->values[p_key_idx].value.out_handle.x = arr[3];
- bt->values[p_key_idx].value.out_handle.y = arr[4];
+ bt->values.write[p_key_idx].value.value = arr[0];
+ bt->values.write[p_key_idx].value.in_handle.x = arr[1];
+ bt->values.write[p_key_idx].value.in_handle.y = arr[2];
+ bt->values.write[p_key_idx].value.out_handle.x = arr[3];
+ bt->values.write[p_key_idx].value.out_handle.y = arr[4];
} break;
case TYPE_AUDIO: {
@@ -1397,16 +1397,16 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
ERR_FAIL_COND(!k.has("end_offset"));
ERR_FAIL_COND(!k.has("stream"));
- at->values[p_key_idx].value.start_offset = k["start_offset"];
- at->values[p_key_idx].value.end_offset = k["end_offset"];
- at->values[p_key_idx].value.stream = k["stream"];
+ at->values.write[p_key_idx].value.start_offset = k["start_offset"];
+ at->values.write[p_key_idx].value.end_offset = k["end_offset"];
+ at->values.write[p_key_idx].value.stream = k["stream"];
} break;
case TYPE_ANIMATION: {
AnimationTrack *at = static_cast<AnimationTrack *>(t);
- at->values[p_key_idx].value = p_value;
+ at->values.write[p_key_idx].value = p_value;
} break;
}
@@ -1423,20 +1423,20 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra
TransformTrack *tt = static_cast<TransformTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, tt->transforms.size());
- tt->transforms[p_key_idx].transition = p_transition;
+ tt->transforms.write[p_key_idx].transition = p_transition;
} break;
case TYPE_VALUE: {
ValueTrack *vt = static_cast<ValueTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, vt->values.size());
- vt->values[p_key_idx].transition = p_transition;
+ vt->values.write[p_key_idx].transition = p_transition;
} break;
case TYPE_METHOD: {
MethodTrack *mt = static_cast<MethodTrack *>(t);
ERR_FAIL_INDEX(p_key_idx, mt->methods.size());
- mt->methods[p_key_idx].transition = p_transition;
+ mt->methods.write[p_key_idx].transition = p_transition;
} break;
case TYPE_BEZIER:
@@ -2210,7 +2210,7 @@ void Animation::bezier_track_set_key_value(int p_track, int p_index, float p_val
ERR_FAIL_INDEX(p_index, bt->values.size());
- bt->values[p_index].value.value = p_value;
+ bt->values.write[p_index].value.value = p_value;
emit_changed();
}
@@ -2224,9 +2224,9 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V
ERR_FAIL_INDEX(p_index, bt->values.size());
- bt->values[p_index].value.in_handle = p_handle;
+ bt->values.write[p_index].value.in_handle = p_handle;
if (bt->values[p_index].value.in_handle.x > 0) {
- bt->values[p_index].value.in_handle.x = 0;
+ bt->values.write[p_index].value.in_handle.x = 0;
}
emit_changed();
}
@@ -2240,9 +2240,9 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const
ERR_FAIL_INDEX(p_index, bt->values.size());
- bt->values[p_index].value.out_handle = p_handle;
+ bt->values.write[p_index].value.out_handle = p_handle;
if (bt->values[p_index].value.out_handle.x < 0) {
- bt->values[p_index].value.out_handle.x = 0;
+ bt->values.write[p_index].value.out_handle.x = 0;
}
emit_changed();
}
@@ -2329,13 +2329,14 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const {
int iterations = 10;
- float low = 0;
- float high = bt->values[idx + 1].time - bt->values[idx].time;
+ float duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes
+ float low = 0; // 0% of the current animation segment
+ float high = 1; // 100% of the current animation segment
float middle = 0;
Vector2 start(0, bt->values[idx].value.value);
Vector2 start_out = start + bt->values[idx].value.out_handle;
- Vector2 end(high, bt->values[idx + 1].value.value);
+ Vector2 end(duration, bt->values[idx + 1].value.value);
Vector2 end_in = end + bt->values[idx + 1].value.in_handle;
//narrow high and low as much as possible
@@ -2355,7 +2356,6 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const {
//interpolate the result:
Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end);
Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end);
-
float c = (t - low_pos.x) / (high_pos.x - low_pos.x);
return low_pos.linear_interpolate(high_pos, c).y;
@@ -2363,7 +2363,6 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const {
int Animation::audio_track_insert_key(int p_track, float p_time, const RES &p_stream, float p_start_offset, float p_end_offset) {
- print_line("really insert key? ");
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
ERR_FAIL_COND_V(t->type != TYPE_AUDIO, -1);
@@ -2397,7 +2396,7 @@ void Animation::audio_track_set_key_stream(int p_track, int p_key, const RES &p_
ERR_FAIL_INDEX(p_key, at->values.size());
- at->values[p_key].value.stream = p_stream;
+ at->values.write[p_key].value.stream = p_stream;
emit_changed();
}
@@ -2415,7 +2414,7 @@ void Animation::audio_track_set_key_start_offset(int p_track, int p_key, float p
if (p_offset < 0)
p_offset = 0;
- at->values[p_key].value.start_offset = p_offset;
+ at->values.write[p_key].value.start_offset = p_offset;
emit_changed();
}
@@ -2433,7 +2432,7 @@ void Animation::audio_track_set_key_end_offset(int p_track, int p_key, float p_o
if (p_offset < 0)
p_offset = 0;
- at->values[p_key].value.end_offset = p_offset;
+ at->values.write[p_key].value.end_offset = p_offset;
emit_changed();
}
@@ -2506,7 +2505,7 @@ void Animation::animation_track_set_key_animation(int p_track, int p_key, const
ERR_FAIL_INDEX(p_key, at->values.size());
- at->values[p_key].value = p_animation;
+ at->values.write[p_key].value = p_animation;
emit_changed();
}
@@ -2551,7 +2550,7 @@ void Animation::track_move_up(int p_track) {
if (p_track >= 0 && p_track < (tracks.size() - 1)) {
- SWAP(tracks[p_track], tracks[p_track + 1]);
+ SWAP(tracks.write[p_track], tracks.write[p_track + 1]);
}
emit_changed();
@@ -2586,7 +2585,7 @@ void Animation::track_move_down(int p_track) {
if (p_track > 0 && p_track < tracks.size()) {
- SWAP(tracks[p_track], tracks[p_track - 1]);
+ SWAP(tracks.write[p_track], tracks.write[p_track - 1]);
}
emit_changed();
}
@@ -2597,7 +2596,7 @@ void Animation::track_swap(int p_track, int p_with_track) {
ERR_FAIL_INDEX(p_with_track, tracks.size());
if (p_track == p_with_track)
return;
- SWAP(tracks[p_track], tracks[p_with_track]);
+ SWAP(tracks.write[p_track], tracks.write[p_with_track]);
emit_changed();
}
@@ -2907,8 +2906,6 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
//able to optimize more
erase = false;
} else {
-
- //print_line(itos(i)+"because of interp");
}
}
}
@@ -2928,9 +2925,9 @@ void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err,
for (int i = 1; i < tt->transforms.size() - 1; i++) {
- TKey<TransformKey> &t0 = tt->transforms[i - 1];
- TKey<TransformKey> &t1 = tt->transforms[i];
- TKey<TransformKey> &t2 = tt->transforms[i + 1];
+ TKey<TransformKey> &t0 = tt->transforms.write[i - 1];
+ TKey<TransformKey> &t1 = tt->transforms.write[i];
+ TKey<TransformKey> &t2 = tt->transforms.write[i + 1];
bool erase = _transform_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle, norm);
if (erase && !prev_erased) {
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index 02a9e4d69b..e6a4b01deb 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -29,6 +29,8 @@
/*************************************************************************/
#include "audio_stream_sample.h"
+#include "io/marshalls.h"
+#include "os/file_access.h"
void AudioStreamPlaybackSample::start(float p_from_pos) {
@@ -509,6 +511,76 @@ PoolVector<uint8_t> AudioStreamSample::get_data() const {
return pv;
}
+void AudioStreamSample::save_to_wav(String p_path) {
+ if (format == AudioStreamSample::FORMAT_IMA_ADPCM) {
+ WARN_PRINTS("Saving IMA_ADPC samples are not supported yet");
+ return;
+ }
+
+ int sub_chunk_2_size = data_bytes; //Subchunk2Size = Size of data in bytes
+
+ // Format code
+ // 1:PCM format (for 8 or 16 bit)
+ // 3:IEEE float format
+ int format_code = (format == FORMAT_IMA_ADPCM) ? 3 : 1;
+
+ int n_channels = stereo ? 2 : 1;
+
+ long sample_rate = mix_rate;
+
+ int byte_pr_sample = 0;
+ switch (format) {
+ case AudioStreamSample::FORMAT_8_BITS: byte_pr_sample = 1; break;
+ case AudioStreamSample::FORMAT_16_BITS: byte_pr_sample = 2; break;
+ case AudioStreamSample::FORMAT_IMA_ADPCM: byte_pr_sample = 4; break;
+ }
+
+ String file_path = p_path;
+ if (!(file_path.substr(file_path.length() - 4, 4) == ".wav")) {
+ file_path += ".wav";
+ }
+
+ Error err;
+ FileAccess *file = FileAccess::open(file_path, FileAccess::WRITE, &err); //Overrides existing file if present
+
+ // Create WAV Header
+ file->store_string("RIFF"); //ChunkID
+ file->store_32(sub_chunk_2_size + 36); //ChunkSize = 36 + SubChunk2Size (size of entire file minus the 8 bits for this and previous header)
+ file->store_string("WAVE"); //Format
+ file->store_string("fmt "); //Subchunk1ID
+ file->store_32(16); //Subchunk1Size = 16
+ file->store_16(format_code); //AudioFormat
+ file->store_16(n_channels); //Number of Channels
+ file->store_32(sample_rate); //SampleRate
+ file->store_32(sample_rate * n_channels * byte_pr_sample); //ByteRate
+ file->store_16(n_channels * byte_pr_sample); //BlockAlign = NumChannels * BytePrSample
+ file->store_16(byte_pr_sample * 8); //BitsPerSample
+ file->store_string("data"); //Subchunk2ID
+ file->store_32(sub_chunk_2_size); //Subchunk2Size
+
+ // Add data
+ PoolVector<uint8_t>::Read read_data = get_data().read();
+ switch (format) {
+ case AudioStreamSample::FORMAT_8_BITS:
+ for (int i = 0; i < data_bytes; i++) {
+ uint8_t data_point = (read_data[i] + 128);
+ file->store_8(data_point);
+ }
+ break;
+ case AudioStreamSample::FORMAT_16_BITS:
+ for (int i = 0; i < data_bytes / 2; i++) {
+ uint16_t data_point = decode_uint16(&read_data[i * 2]);
+ file->store_16(data_point);
+ }
+ break;
+ case AudioStreamSample::FORMAT_IMA_ADPCM:
+ //Unimplemented
+ break;
+ }
+
+ file->close();
+}
+
Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() {
Ref<AudioStreamPlaybackSample> sample;
@@ -545,6 +617,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("save_to_wav", "path"), &AudioStreamSample::save_to_wav);
+
ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "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");
diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h
index 5fe65c194e..a27acc92b7 100644
--- a/scene/resources/audio_stream_sample.h
+++ b/scene/resources/audio_stream_sample.h
@@ -140,6 +140,8 @@ public:
void set_data(const PoolVector<uint8_t> &p_data);
PoolVector<uint8_t> get_data() const;
+ void save_to_wav(String p_path);
+
virtual Ref<AudioStreamPlayback> instance_playback();
virtual String get_stream_name() const;
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index 29ffefd9d6..5694099754 100644
--- a/scene/resources/bit_mask.cpp
+++ b/scene/resources/bit_mask.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "bit_mask.h"
+
#include "io/image_loader.h"
void BitMap::create(const Size2 &p_size) {
@@ -130,7 +131,7 @@ void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
else
b &= ~(1 << bbit);
- bitmask[bbyte] = b;
+ bitmask.write[bbyte] = b;
}
bool BitMap::get_bit(const Point2 &p_pos) const {
@@ -189,13 +190,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
{ //square value
/*
- checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
- +---+---+
- | 1 | 2 |
- +---+---+
- | 4 | 8 | <- current pixel (curx,cury)
- +---+---+
- */
+ 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);
@@ -215,13 +216,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
case 5:
case 13:
/* going UP with these cases:
- 1 5 13
- +---+---+ +---+---+ +---+---+
- | 1 | | | 1 | | | 1 | |
- +---+---+ +---+---+ +---+---+
- | | | | 4 | | | 4 | 8 |
- +---+---+ +---+---+ +---+---+
- */
+ 1 5 13
+ +---+---+ +---+---+ +---+---+
+ | 1 | | | 1 | | | 1 | |
+ +---+---+ +---+---+ +---+---+
+ | | | | 4 | | | 4 | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
stepx = 0;
stepy = -1;
break;
@@ -230,13 +231,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
case 10:
case 11:
/* going DOWN with these cases:
- 8 10 11
- +---+---+ +---+---+ +---+---+
- | | | | | 2 | | 1 | 2 |
- +---+---+ +---+---+ +---+---+
- | | 8 | | | 8 | | | 8 |
- +---+---+ +---+---+ +---+---+
- */
+ 8 10 11
+ +---+---+ +---+---+ +---+---+
+ | | | | | 2 | | 1 | 2 |
+ +---+---+ +---+---+ +---+---+
+ | | 8 | | | 8 | | | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
stepx = 0;
stepy = 1;
break;
@@ -245,13 +246,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
case 12:
case 14:
/* going LEFT with these cases:
- 4 12 14
- +---+---+ +---+---+ +---+---+
- | | | | | | | | 2 |
- +---+---+ +---+---+ +---+---+
- | 4 | | | 4 | 8 | | 4 | 8 |
- +---+---+ +---+---+ +---+---+
- */
+ 4 12 14
+ +---+---+ +---+---+ +---+---+
+ | | | | | | | | 2 |
+ +---+---+ +---+---+ +---+---+
+ | 4 | | | 4 | 8 | | 4 | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
stepx = -1;
stepy = 0;
break;
@@ -260,25 +261,25 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
case 3:
case 7:
/* going RIGHT with these cases:
- 2 3 7
- +---+---+ +---+---+ +---+---+
- | | 2 | | 1 | 2 | | 1 | 2 |
- +---+---+ +---+---+ +---+---+
- | | | | | | | 4 | |
- +---+---+ +---+---+ +---+---+
- */
+ 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
- */
+ +---+---+
+ | 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;
@@ -293,14 +294,14 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
break;
case 6:
/*
- 6
- +---+---+
- | | 2 |
- +---+---+
- | 4 | |
- +---+---+
- this normally go RIGHT, but if its coming from UP, it should go LEFT
- */
+ 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;
@@ -322,8 +323,8 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
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);
+ _points.write[_points.size() - 1].x = (float)(curx - rect.position.x);
+ _points.write[_points.size() - 1].y = (float)(cury + rect.position.y);
} else {
_points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y)));
}
@@ -373,11 +374,11 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
Vector<Vector2> left, right;
left.resize(index);
for (int i = 0; i < index; i++) {
- left[i] = v[i];
+ left.write[i] = v[i];
}
right.resize(v.size() - index);
for (int i = 0; i < right.size(); i++) {
- right[i] = v[index + i];
+ right.write[i] = v[index + i];
}
Vector<Vector2> r1 = rdp(left, optimization);
Vector<Vector2> r2 = rdp(right, optimization);
@@ -385,7 +386,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
int middle = r1.size();
r1.resize(r1.size() + r2.size());
for (int i = 0; i < r2.size(); i++) {
- r1[middle + i] = r2[i];
+ r1.write[middle + i] = r2[i];
}
return r1;
} else {
@@ -412,37 +413,93 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect,
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.write[0].y = last.y;
result.resize(result.size() - 1);
}
return result;
}
+struct FillBitsStackEntry {
+ Point2i pos;
+ int i;
+ int j;
+};
+
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++) {
+ // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps
+ PoolVector<FillBitsStackEntry> stack;
+ // Tracking size since we won't be shrinking the stack vector
+ int stack_size = 0;
- 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;
+ Point2i pos = p_pos;
+ int next_i;
+ int next_j;
- if (p_map->get_bit(Vector2(i, j)))
- continue;
+ bool reenter = true;
+ bool popped = false;
+ do {
+ if (reenter) {
+ next_i = pos.x - 1;
+ next_j = pos.y - 1;
+ reenter = false;
+ }
+
+ for (int i = next_i; i <= pos.x + 1; i++) {
+ for (int j = next_j; j <= pos.y + 1; j++) {
+ if (popped) {
+ // The next loop over j must start normally
+ next_j = pos.y;
+ popped = false;
+ // Skip because an iteration was already executed with current counter values
+ 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);
+ 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);
+
+ FillBitsStackEntry se = { pos, i, j };
+ stack.resize(MAX(stack_size + 1, stack.size()));
+ stack.set(stack_size, se);
+ stack_size++;
+
+ pos = Point2i(i, j);
+ reenter = true;
+ break;
+ }
+ }
+ if (reenter) {
+ break;
}
}
- }
+ if (!reenter) {
+ if (stack_size) {
+ FillBitsStackEntry se = stack.get(stack_size - 1);
+ stack_size--;
+ pos = se.pos;
+ next_i = se.i;
+ next_j = se.j;
+ popped = true;
+ }
+ }
+ } while (reenter || popped);
+
+ print_verbose("BitMap: Max stack size: " + itos(stack.size()));
}
+
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_verbose("BitMap: Rect: " + r);
- print_line("Rect: " + r);
Point2i from;
Ref<BitMap> fill;
fill.instance();
@@ -454,9 +511,9 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
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()));
+ print_verbose("BitMap: Pre reduce: " + itos(polygon.size()));
polygon = reduce(polygon, r, p_epsilon);
- print_line("post reduce: " + itos(polygon.size()));
+ print_verbose("BitMap: Post reduce: " + itos(polygon.size()));
polygons.push_back(polygon);
fill_bits(this, fill, Point2i(j, i), r);
}
@@ -510,6 +567,34 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
}
}
+Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
+
+ Vector<Vector<Vector2> > result = clip_opaque_to_polygons(p_rect, p_epsilon);
+
+ // Convert result to bindable types
+
+ Array result_array;
+ result_array.resize(result.size());
+ for (int i = 0; i < result.size(); i++) {
+
+ const Vector<Vector2> &polygon = result[i];
+
+ PoolVector2Array polygon_array;
+ polygon_array.resize(polygon.size());
+
+ {
+ PoolVector2Array::Write w = polygon_array.write();
+ for (int j = 0; j < polygon.size(); j++) {
+ w[j] = polygon[j];
+ }
+ }
+
+ result_array[i] = polygon_array;
+ }
+
+ return result_array;
+}
+
void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
@@ -526,6 +611,9 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data);
+ ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask);
+ ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0));
+
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h
index dcd5edb4fb..40f0bfb04a 100644
--- a/scene/resources/bit_mask.h
+++ b/scene/resources/bit_mask.h
@@ -46,6 +46,8 @@ class BitMap : public Resource {
Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
+ Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const;
+
protected:
void _set_data(const Dictionary &p_d);
Dictionary _get_data() const;
diff --git a/scene/resources/color_ramp.cpp b/scene/resources/color_ramp.cpp
index b2f586d02d..4a43303d84 100644
--- a/scene/resources/color_ramp.cpp
+++ b/scene/resources/color_ramp.cpp
@@ -40,10 +40,10 @@
Gradient::Gradient() {
//Set initial color ramp transition from black to white
points.resize(2);
- points[0].color = Color(0, 0, 0, 1);
- points[0].offset = 0;
- points[1].color = Color(1, 1, 1, 1);
- points[1].offset = 1;
+ points.write[0].color = Color(0, 0, 0, 1);
+ points.write[0].offset = 0;
+ points.write[1].color = Color(1, 1, 1, 1);
+ points.write[1].offset = 1;
is_sorted = true;
}
@@ -79,7 +79,7 @@ Vector<float> Gradient::get_offsets() const {
Vector<float> offsets;
offsets.resize(points.size());
for (int i = 0; i < points.size(); i++) {
- offsets[i] = points[i].offset;
+ offsets.write[i] = points[i].offset;
}
return offsets;
}
@@ -88,7 +88,7 @@ Vector<Color> Gradient::get_colors() const {
Vector<Color> colors;
colors.resize(points.size());
for (int i = 0; i < points.size(); i++) {
- colors[i] = points[i].color;
+ colors.write[i] = points[i].color;
}
return colors;
}
@@ -96,7 +96,7 @@ Vector<Color> Gradient::get_colors() const {
void Gradient::set_offsets(const Vector<float> &p_offsets) {
points.resize(p_offsets.size());
for (int i = 0; i < points.size(); i++) {
- points[i].offset = p_offsets[i];
+ points.write[i].offset = p_offsets[i];
}
is_sorted = false;
emit_signal(CoreStringNames::get_singleton()->changed);
@@ -107,7 +107,7 @@ void Gradient::set_colors(const Vector<Color> &p_colors) {
is_sorted = false;
points.resize(p_colors.size());
for (int i = 0; i < points.size(); i++) {
- points[i].color = p_colors[i];
+ points.write[i].color = p_colors[i];
}
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -144,7 +144,7 @@ void Gradient::set_points(Vector<Gradient::Point> &p_points) {
void Gradient::set_offset(int pos, const float offset) {
if (points.size() <= pos)
points.resize(pos + 1);
- points[pos].offset = offset;
+ points.write[pos].offset = offset;
is_sorted = false;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -160,7 +160,7 @@ void Gradient::set_color(int pos, const Color &color) {
points.resize(pos + 1);
is_sorted = false;
}
- points[pos].color = color;
+ points.write[pos].color = color;
emit_signal(CoreStringNames::get_singleton()->changed);
}
diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h
index c042a0d3d0..070ad7f0d3 100644
--- a/scene/resources/color_ramp.h
+++ b/scene/resources/color_ramp.h
@@ -98,7 +98,7 @@ public:
while (low <= high) {
middle = (low + high) / 2;
- Point &point = points[middle];
+ const Point &point = points[middle];
if (point.offset > p_offset) {
high = middle - 1; //search low end of array
} else if (point.offset < p_offset) {
@@ -118,8 +118,8 @@ public:
return points[points.size() - 1].color;
if (first < 0)
return points[0].color;
- Point &pointFirst = points[first];
- Point &pointSecond = points[second];
+ const Point &pointFirst = points[first];
+ const Point &pointSecond = points[second];
return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset));
}
diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp
index 935f041837..bc9e2848b3 100644
--- a/scene/resources/concave_polygon_shape.cpp
+++ b/scene/resources/concave_polygon_shape.cpp
@@ -56,8 +56,8 @@ Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() {
int idx = 0;
for (Set<DrawEdge>::Element *E = edges.front(); E; E = E->next()) {
- points[idx + 0] = E->get().a;
- points[idx + 1] = E->get().b;
+ points.write[idx + 0] = E->get().a;
+ points.write[idx + 1] = E->get().b;
idx += 2;
}
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index a2e0996996..fa9369d3bc 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -46,8 +46,8 @@ Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
for (int i = 0; i < md.edges.size(); i++) {
- lines[i * 2 + 0] = md.vertices[md.edges[i].a];
- lines[i * 2 + 1] = md.vertices[md.edges[i].b];
+ lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
+ lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
}
return lines;
}
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 7f902fc982..d8989bf062 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -153,25 +153,25 @@ void Curve::clean_dupes() {
void Curve::set_point_left_tangent(int i, real_t tangent) {
ERR_FAIL_INDEX(i, _points.size());
- _points[i].left_tangent = tangent;
- _points[i].left_mode = TANGENT_FREE;
+ _points.write[i].left_tangent = tangent;
+ _points.write[i].left_mode = TANGENT_FREE;
mark_dirty();
}
void Curve::set_point_right_tangent(int i, real_t tangent) {
ERR_FAIL_INDEX(i, _points.size());
- _points[i].right_tangent = tangent;
- _points[i].right_mode = TANGENT_FREE;
+ _points.write[i].right_tangent = tangent;
+ _points.write[i].right_mode = TANGENT_FREE;
mark_dirty();
}
void Curve::set_point_left_mode(int i, TangentMode p_mode) {
ERR_FAIL_INDEX(i, _points.size());
- _points[i].left_mode = p_mode;
+ _points.write[i].left_mode = p_mode;
if (i > 0) {
if (p_mode == TANGENT_LINEAR) {
Vector2 v = (_points[i - 1].pos - _points[i].pos).normalized();
- _points[i].left_tangent = v.y / v.x;
+ _points.write[i].left_tangent = v.y / v.x;
}
}
mark_dirty();
@@ -179,11 +179,11 @@ void Curve::set_point_left_mode(int i, TangentMode p_mode) {
void Curve::set_point_right_mode(int i, TangentMode p_mode) {
ERR_FAIL_INDEX(i, _points.size());
- _points[i].right_mode = p_mode;
+ _points.write[i].right_mode = p_mode;
if (i + 1 < _points.size()) {
if (p_mode == TANGENT_LINEAR) {
Vector2 v = (_points[i + 1].pos - _points[i].pos).normalized();
- _points[i].right_tangent = v.y / v.x;
+ _points.write[i].right_tangent = v.y / v.x;
}
}
mark_dirty();
@@ -222,7 +222,7 @@ void Curve::clear_points() {
void Curve::set_point_value(int p_index, real_t pos) {
ERR_FAIL_INDEX(p_index, _points.size());
- _points[p_index].pos.y = pos;
+ _points.write[p_index].pos.y = pos;
update_auto_tangents(p_index);
mark_dirty();
}
@@ -232,10 +232,10 @@ int Curve::set_point_offset(int p_index, float offset) {
Point p = _points[p_index];
remove_point(p_index);
int i = add_point(Vector2(offset, p.pos.y));
- _points[i].left_tangent = p.left_tangent;
- _points[i].right_tangent = p.right_tangent;
- _points[i].left_mode = p.left_mode;
- _points[i].right_mode = p.right_mode;
+ _points.write[i].left_tangent = p.left_tangent;
+ _points.write[i].right_tangent = p.right_tangent;
+ _points.write[i].left_mode = p.left_mode;
+ _points.write[i].right_mode = p.right_mode;
if (p_index != i)
update_auto_tangents(p_index);
update_auto_tangents(i);
@@ -254,7 +254,7 @@ Curve::Point Curve::get_point(int p_index) const {
void Curve::update_auto_tangents(int i) {
- Point &p = _points[i];
+ Point &p = _points.write[i];
if (i > 0) {
if (p.left_mode == TANGENT_LINEAR) {
@@ -263,7 +263,7 @@ void Curve::update_auto_tangents(int i) {
}
if (_points[i - 1].right_mode == TANGENT_LINEAR) {
Vector2 v = (_points[i - 1].pos - p.pos).normalized();
- _points[i - 1].right_tangent = v.y / v.x;
+ _points.write[i - 1].right_tangent = v.y / v.x;
}
}
@@ -274,7 +274,7 @@ void Curve::update_auto_tangents(int i) {
}
if (_points[i + 1].left_mode == TANGENT_LINEAR) {
Vector2 v = (_points[i + 1].pos - p.pos).normalized();
- _points[i + 1].left_tangent = v.y / v.x;
+ _points.write[i + 1].left_tangent = v.y / v.x;
}
}
}
@@ -402,7 +402,7 @@ void Curve::set_data(Array input) {
for (int j = 0; j < _points.size(); ++j) {
- Point &p = _points[j];
+ Point &p = _points.write[j];
int i = j * ELEMS;
p.pos = input[i];
@@ -426,12 +426,12 @@ void Curve::bake() {
for (int i = 1; i < _bake_resolution - 1; ++i) {
real_t x = i / static_cast<real_t>(_bake_resolution);
real_t y = interpolate(x);
- _baked_cache[i] = y;
+ _baked_cache.write[i] = y;
}
if (_points.size() != 0) {
- _baked_cache[0] = _points[0].pos.y;
- _baked_cache[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y;
+ _baked_cache.write[0] = _points[0].pos.y;
+ _baked_cache.write[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y;
}
_baked_cache_dirty = false;
@@ -479,6 +479,16 @@ real_t Curve::interpolate_baked(real_t offset) {
}
}
+void Curve::ensure_default_setup(float p_min, float p_max) {
+ if (_points.size() == 0 && _min_value == 0 && _max_value == 1) {
+
+ add_point(Vector2(0, 1));
+ add_point(Vector2(1, 1));
+ set_min_value(p_min);
+ set_max_value(p_max);
+ }
+}
+
void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_point", "position", "left_tangent", "right_tangent", "left_mode", "right_mode"), &Curve::add_point, DEFVAL(0), DEFVAL(0), DEFVAL(TANGENT_FREE), DEFVAL(TANGENT_FREE));
@@ -543,7 +553,7 @@ void Curve2D::set_point_position(int p_index, const Vector2 &p_pos) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].pos = p_pos;
+ points.write[p_index].pos = p_pos;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -557,7 +567,7 @@ void Curve2D::set_point_in(int p_index, const Vector2 &p_in) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].in = p_in;
+ points.write[p_index].in = p_in;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -571,7 +581,7 @@ void Curve2D::set_point_out(int p_index, const Vector2 &p_out) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].out = p_out;
+ points.write[p_index].out = p_out;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -920,9 +930,9 @@ void Curve2D::_set_data(const Dictionary &p_data) {
for (int i = 0; i < points.size(); i++) {
- points[i].in = r[i * 3 + 0];
- points[i].out = r[i * 3 + 1];
- points[i].pos = r[i * 3 + 2];
+ points.write[i].in = r[i * 3 + 0];
+ points.write[i].out = r[i * 3 + 1];
+ points.write[i].pos = r[i * 3 + 2];
}
baked_cache_dirty = true;
@@ -942,7 +952,7 @@ PoolVector2Array Curve2D::tessellate(int p_max_stages, float p_tolerance) const
int pc = 1;
for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment2d(midpoints[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ _bake_segment2d(midpoints.write[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance);
pc++;
pc += midpoints[i].size();
}
@@ -1039,7 +1049,7 @@ void Curve3D::set_point_position(int p_index, const Vector3 &p_pos) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].pos = p_pos;
+ points.write[p_index].pos = p_pos;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -1053,7 +1063,7 @@ void Curve3D::set_point_tilt(int p_index, float p_tilt) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].tilt = p_tilt;
+ points.write[p_index].tilt = p_tilt;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -1067,7 +1077,7 @@ void Curve3D::set_point_in(int p_index, const Vector3 &p_in) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].in = p_in;
+ points.write[p_index].in = p_in;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -1081,7 +1091,7 @@ void Curve3D::set_point_out(int p_index, const Vector3 &p_out) {
ERR_FAIL_INDEX(p_index, points.size());
- points[p_index].out = p_out;
+ points.write[p_index].out = p_out;
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -1611,10 +1621,10 @@ void Curve3D::_set_data(const Dictionary &p_data) {
for (int i = 0; i < points.size(); i++) {
- points[i].in = r[i * 3 + 0];
- points[i].out = r[i * 3 + 1];
- points[i].pos = r[i * 3 + 2];
- points[i].tilt = rt[i];
+ points.write[i].in = r[i * 3 + 0];
+ points.write[i].out = r[i * 3 + 1];
+ points.write[i].pos = r[i * 3 + 2];
+ points.write[i].tilt = rt[i];
}
baked_cache_dirty = true;
@@ -1634,7 +1644,7 @@ PoolVector3Array Curve3D::tessellate(int p_max_stages, float p_tolerance) const
int pc = 1;
for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d(midpoints[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance);
pc++;
pc += midpoints[i].size();
}
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 9cb12a4345..058c4f1bc2 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -128,6 +128,8 @@ public:
void set_bake_resolution(int p_resolution);
real_t interpolate_baked(real_t offset);
+ void ensure_default_setup(float p_min, float p_max);
+
protected:
static void _bind_methods();
diff --git a/scene/resources/cylinder_shape.cpp b/scene/resources/cylinder_shape.cpp
new file mode 100644
index 0000000000..f760462d49
--- /dev/null
+++ b/scene/resources/cylinder_shape.cpp
@@ -0,0 +1,116 @@
+/*************************************************************************/
+/* cylinder_shape.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 "cylinder_shape.h"
+#include "servers/physics_server.h"
+
+Vector<Vector3> CylinderShape::_gen_debug_mesh_lines() {
+
+ float radius = get_radius();
+ float height = get_height();
+
+ Vector<Vector3> points;
+
+ Vector3 d(0, height * 0.5, 0);
+ for (int i = 0; i < 360; i++) {
+
+ float ra = Math::deg2rad((float)i);
+ float rb = Math::deg2rad((float)i + 1);
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(b.x, 0, b.y) + d);
+
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ points.push_back(Vector3(b.x, 0, b.y) - d);
+
+ if (i % 90 == 0) {
+
+ points.push_back(Vector3(a.x, 0, a.y) + d);
+ points.push_back(Vector3(a.x, 0, a.y) - d);
+ }
+ }
+
+ return points;
+}
+
+void CylinderShape::_update_shape() {
+
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
+}
+
+void CylinderShape::set_radius(float p_radius) {
+
+ radius = p_radius;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("radius");
+}
+
+float CylinderShape::get_radius() const {
+
+ return radius;
+}
+
+void CylinderShape::set_height(float p_height) {
+
+ height = p_height;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("height");
+}
+
+float CylinderShape::get_height() const {
+
+ return height;
+}
+
+void CylinderShape::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape::set_radius);
+ ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape::get_radius);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape::set_height);
+ ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape::get_height);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height");
+}
+
+CylinderShape::CylinderShape() :
+ Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CYLINDER)) {
+
+ radius = 1.0;
+ height = 2.0;
+ _update_shape();
+}
diff --git a/scene/resources/cylinder_shape.h b/scene/resources/cylinder_shape.h
new file mode 100644
index 0000000000..f510758e91
--- /dev/null
+++ b/scene/resources/cylinder_shape.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* cylinder_shape.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 CYLINDER_SHAPE_H
+#define CYLINDER_SHAPE_H
+
+#include "scene/resources/shape.h"
+
+class CylinderShape : public Shape {
+
+ GDCLASS(CylinderShape, Shape);
+ float radius;
+ float height;
+
+protected:
+ static void _bind_methods();
+ virtual void _update_shape();
+
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
+
+public:
+ void set_radius(float p_radius);
+ float get_radius() const;
+ void set_height(float p_height);
+ float get_height() const;
+
+ CylinderShape();
+};
+
+#endif // CYLINDER_SHAPE_H
diff --git a/scene/resources/default_theme/arrow_down.png b/scene/resources/default_theme/arrow_down.png
index fc837d120a..bfb87a4761 100644
--- a/scene/resources/default_theme/arrow_down.png
+++ b/scene/resources/default_theme/arrow_down.png
Binary files differ
diff --git a/scene/resources/default_theme/arrow_right.png b/scene/resources/default_theme/arrow_right.png
index ebe6e26ace..1e4c8e5529 100644
--- a/scene/resources/default_theme/arrow_right.png
+++ b/scene/resources/default_theme/arrow_right.png
Binary files differ
diff --git a/scene/resources/default_theme/background.png b/scene/resources/default_theme/background.png
index 03cfab1de3..6c5f43e3ce 100644
--- a/scene/resources/default_theme/background.png
+++ b/scene/resources/default_theme/background.png
Binary files differ
diff --git a/scene/resources/default_theme/base_green.png b/scene/resources/default_theme/base_green.png
index d03d6f08d8..03a5b313d7 100644
--- a/scene/resources/default_theme/base_green.png
+++ b/scene/resources/default_theme/base_green.png
Binary files differ
diff --git a/scene/resources/default_theme/button_disabled.png b/scene/resources/default_theme/button_disabled.png
index d75e76989d..708748dfe9 100644
--- a/scene/resources/default_theme/button_disabled.png
+++ b/scene/resources/default_theme/button_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/button_focus.png b/scene/resources/default_theme/button_focus.png
index 44e354be95..70e16b953b 100644
--- a/scene/resources/default_theme/button_focus.png
+++ b/scene/resources/default_theme/button_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/button_hover.png b/scene/resources/default_theme/button_hover.png
index 6e609f435f..ef226e3caf 100644
--- a/scene/resources/default_theme/button_hover.png
+++ b/scene/resources/default_theme/button_hover.png
Binary files differ
diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png
index 92482aaf28..7d0bd16221 100644
--- a/scene/resources/default_theme/button_normal.png
+++ b/scene/resources/default_theme/button_normal.png
Binary files differ
diff --git a/scene/resources/default_theme/checked.png b/scene/resources/default_theme/checked.png
index 93e291a29e..bde031b6a2 100644
--- a/scene/resources/default_theme/checked.png
+++ b/scene/resources/default_theme/checked.png
Binary files differ
diff --git a/scene/resources/default_theme/checker_bg.png b/scene/resources/default_theme/checker_bg.png
index f58dfed29c..3eff2f0e08 100644
--- a/scene/resources/default_theme/checker_bg.png
+++ b/scene/resources/default_theme/checker_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/close.png b/scene/resources/default_theme/close.png
index 5ac6357dcd..4d4ac4a551 100644
--- a/scene/resources/default_theme/close.png
+++ b/scene/resources/default_theme/close.png
Binary files differ
diff --git a/scene/resources/default_theme/close_hl.png b/scene/resources/default_theme/close_hl.png
index 5ac6357dcd..4d4ac4a551 100644
--- a/scene/resources/default_theme/close_hl.png
+++ b/scene/resources/default_theme/close_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/color_picker_sample.png b/scene/resources/default_theme/color_picker_sample.png
index b145a3e384..e6ec28d307 100644
--- a/scene/resources/default_theme/color_picker_sample.png
+++ b/scene/resources/default_theme/color_picker_sample.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index d64e6970bf..0eee2ae393 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -434,9 +434,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color_selected", "LineEdit", Color(0, 0, 0));
theme->set_color("cursor_color", "LineEdit", control_font_color_hover);
theme->set_color("selection_color", "LineEdit", font_color_selection);
+ theme->set_color("clear_button_color", "LineEdit", control_font_color);
+ theme->set_color("clear_button_color_pressed", "LineEdit", control_font_color_pressed);
theme->set_constant("minimum_spaces", "LineEdit", 12 * scale);
+ theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png));
+
// ProgressBar
theme->set_stylebox("bg", "ProgressBar", make_stylebox(progress_bar_png, 4, 4, 4, 4, 0, 0, 0, 0));
@@ -476,6 +480,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("symbol_color", "TextEdit", control_font_color_hover);
theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2));
theme->set_color("line_number_color", "TextEdit", Color::html("66aaaaaa"));
+ theme->set_color("safe_line_number_color", "TextEdit", Color::html("99aac8aa"));
theme->set_color("function_color", "TextEdit", Color::html("66a2ce"));
theme->set_color("member_variable_color", "TextEdit", Color::html("e64e59"));
theme->set_color("number_color", "TextEdit", Color::html("EB9532"));
@@ -585,6 +590,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("panel_disabled", "PopupMenu", make_stylebox(popup_bg_disabled_png, 4, 4, 4, 4));
theme->set_stylebox("hover", "PopupMenu", selected);
theme->set_stylebox("separator", "PopupMenu", make_stylebox(vseparator_png, 3, 3, 3, 3));
+ theme->set_stylebox("labeled_separator_left", "PopupMenu", make_stylebox(vseparator_png, 0, 0, 0, 0));
+ theme->set_stylebox("labeled_separator_right", "PopupMenu", make_stylebox(vseparator_png, 0, 0, 0, 0));
theme->set_icon("checked", "PopupMenu", make_icon(checked_png));
theme->set_icon("unchecked", "PopupMenu", make_icon(unchecked_png));
@@ -844,7 +851,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("separation", "HBoxContainer", 4 * scale);
theme->set_constant("separation", "VBoxContainer", 4 * scale);
- theme->set_constant("margin_left", "MarginContainer", 8 * scale);
+ theme->set_constant("margin_left", "MarginContainer", 0 * scale);
theme->set_constant("margin_top", "MarginContainer", 0 * scale);
theme->set_constant("margin_right", "MarginContainer", 0 * scale);
theme->set_constant("margin_bottom", "MarginContainer", 0 * scale);
@@ -860,7 +867,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxTexture> ttnc = make_stylebox(full_panel_bg_png, 8, 8, 8, 8);
ttnc->set_draw_center(false);
- theme->set_stylebox("border", "ReferenceRect", make_stylebox(reference_border_png, 4, 4, 4, 4));
theme->set_stylebox("panelnc", "Panel", ttnc);
theme->set_stylebox("panelf", "Panel", tc_sb);
@@ -880,6 +886,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("logo", "Icons", make_icon(logo_png));
+ // Visual Node Ports
+ theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale);
+ theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
+
// Theme
default_icon = make_icon(error_icon_png);
diff --git a/scene/resources/default_theme/dosfont.png b/scene/resources/default_theme/dosfont.png
index 814d2e9060..e2739b94ea 100644
--- a/scene/resources/default_theme/dosfont.png
+++ b/scene/resources/default_theme/dosfont.png
Binary files differ
diff --git a/scene/resources/default_theme/dropdown.png b/scene/resources/default_theme/dropdown.png
index 3a6a2ed778..b5d9ffbbb4 100644
--- a/scene/resources/default_theme/dropdown.png
+++ b/scene/resources/default_theme/dropdown.png
Binary files differ
diff --git a/scene/resources/default_theme/error_icon.png b/scene/resources/default_theme/error_icon.png
index f291362350..7741d00749 100644
--- a/scene/resources/default_theme/error_icon.png
+++ b/scene/resources/default_theme/error_icon.png
Binary files differ
diff --git a/scene/resources/default_theme/focus.png b/scene/resources/default_theme/focus.png
index 5d37028f2d..f51ea89e8f 100644
--- a/scene/resources/default_theme/focus.png
+++ b/scene/resources/default_theme/focus.png
Binary files differ
diff --git a/scene/resources/default_theme/frame_focus.png b/scene/resources/default_theme/frame_focus.png
index 9170db38ed..1b24ba47d8 100644
--- a/scene/resources/default_theme/frame_focus.png
+++ b/scene/resources/default_theme/frame_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/full_panel_bg.png b/scene/resources/default_theme/full_panel_bg.png
index 7f02dc7259..85f753cc13 100644
--- a/scene/resources/default_theme/full_panel_bg.png
+++ b/scene/resources/default_theme/full_panel_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_breakpoint.png b/scene/resources/default_theme/graph_node_breakpoint.png
index 0e36f31bd4..e18c6f42e1 100644
--- a/scene/resources/default_theme/graph_node_breakpoint.png
+++ b/scene/resources/default_theme/graph_node_breakpoint.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png
index 144a8b9c4c..5c962ae1c6 100644
--- a/scene/resources/default_theme/graph_node_close.png
+++ b/scene/resources/default_theme/graph_node_close.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_comment.png b/scene/resources/default_theme/graph_node_comment.png
index f2d6daa259..cdec1d1eac 100644
--- a/scene/resources/default_theme/graph_node_comment.png
+++ b/scene/resources/default_theme/graph_node_comment.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_comment_focus.png b/scene/resources/default_theme/graph_node_comment_focus.png
index a4b7b5a618..472a6b6f53 100644
--- a/scene/resources/default_theme/graph_node_comment_focus.png
+++ b/scene/resources/default_theme/graph_node_comment_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_default.png b/scene/resources/default_theme/graph_node_default.png
index e3a220301f..359bbdc205 100644
--- a/scene/resources/default_theme/graph_node_default.png
+++ b/scene/resources/default_theme/graph_node_default.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png
index 9972b07593..204dd16ac0 100644
--- a/scene/resources/default_theme/graph_node_default_focus.png
+++ b/scene/resources/default_theme/graph_node_default_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_position.png b/scene/resources/default_theme/graph_node_position.png
index 7ec15e2ff4..24c2759be6 100644
--- a/scene/resources/default_theme/graph_node_position.png
+++ b/scene/resources/default_theme/graph_node_position.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png
index f76c9703dd..cc4eb7f753 100644
--- a/scene/resources/default_theme/graph_node_selected.png
+++ b/scene/resources/default_theme/graph_node_selected.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png
index 9d5082cfdb..f33ae3baf3 100644
--- a/scene/resources/default_theme/graph_port.png
+++ b/scene/resources/default_theme/graph_port.png
Binary files differ
diff --git a/scene/resources/default_theme/hseparator.png b/scene/resources/default_theme/hseparator.png
index 99609ac118..d4fd71ace5 100644
--- a/scene/resources/default_theme/hseparator.png
+++ b/scene/resources/default_theme/hseparator.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_bg.png b/scene/resources/default_theme/hslider_bg.png
index 9c2a2df62a..b402bd370d 100644
--- a/scene/resources/default_theme/hslider_bg.png
+++ b/scene/resources/default_theme/hslider_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_grabber.png b/scene/resources/default_theme/hslider_grabber.png
index 2acd33879a..d273b491ee 100644
--- a/scene/resources/default_theme/hslider_grabber.png
+++ b/scene/resources/default_theme/hslider_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_grabber_disabled.png b/scene/resources/default_theme/hslider_grabber_disabled.png
index 0d75182b8f..dddd1a468e 100644
--- a/scene/resources/default_theme/hslider_grabber_disabled.png
+++ b/scene/resources/default_theme/hslider_grabber_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_grabber_hl.png b/scene/resources/default_theme/hslider_grabber_hl.png
index f8a011e64b..e3defb3610 100644
--- a/scene/resources/default_theme/hslider_grabber_hl.png
+++ b/scene/resources/default_theme/hslider_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_tick.png b/scene/resources/default_theme/hslider_tick.png
index f7afd78529..1ba19c37a1 100644
--- a/scene/resources/default_theme/hslider_tick.png
+++ b/scene/resources/default_theme/hslider_tick.png
Binary files differ
diff --git a/scene/resources/default_theme/hsplit_bg.png b/scene/resources/default_theme/hsplit_bg.png
index 7dd1d48b29..a5749f6d5c 100644
--- a/scene/resources/default_theme/hsplit_bg.png
+++ b/scene/resources/default_theme/hsplit_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/hsplitter.png b/scene/resources/default_theme/hsplitter.png
index 71a3914d7e..2287753c9d 100644
--- a/scene/resources/default_theme/hsplitter.png
+++ b/scene/resources/default_theme/hsplitter.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_add.png b/scene/resources/default_theme/icon_add.png
index fa675045bc..eccb69b363 100644
--- a/scene/resources/default_theme/icon_add.png
+++ b/scene/resources/default_theme/icon_add.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_close.png b/scene/resources/default_theme/icon_close.png
index 5ac6357dcd..4d4ac4a551 100644
--- a/scene/resources/default_theme/icon_close.png
+++ b/scene/resources/default_theme/icon_close.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_color_pick.png b/scene/resources/default_theme/icon_color_pick.png
index 15679a9558..46953febb8 100644
--- a/scene/resources/default_theme/icon_color_pick.png
+++ b/scene/resources/default_theme/icon_color_pick.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_folder.png b/scene/resources/default_theme/icon_folder.png
index cc05e98ebb..d1b308e88d 100644
--- a/scene/resources/default_theme/icon_folder.png
+++ b/scene/resources/default_theme/icon_folder.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_parent_folder.png b/scene/resources/default_theme/icon_parent_folder.png
index 47fee1ad81..35d218722e 100644
--- a/scene/resources/default_theme/icon_parent_folder.png
+++ b/scene/resources/default_theme/icon_parent_folder.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_play.png b/scene/resources/default_theme/icon_play.png
index 864e4e4fb9..b9ed6e6d5b 100644
--- a/scene/resources/default_theme/icon_play.png
+++ b/scene/resources/default_theme/icon_play.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_reload.png b/scene/resources/default_theme/icon_reload.png
index 9303fabb9c..bec5f3f4f9 100644
--- a/scene/resources/default_theme/icon_reload.png
+++ b/scene/resources/default_theme/icon_reload.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_snap_grid.png b/scene/resources/default_theme/icon_snap_grid.png
index 44db9bdfdc..0680317d86 100644
--- a/scene/resources/default_theme/icon_snap_grid.png
+++ b/scene/resources/default_theme/icon_snap_grid.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_stop.png b/scene/resources/default_theme/icon_stop.png
index 1f194d0e14..0c1371ceb9 100644
--- a/scene/resources/default_theme/icon_stop.png
+++ b/scene/resources/default_theme/icon_stop.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_zoom_less.png b/scene/resources/default_theme/icon_zoom_less.png
index 888ddc995d..03119c60ca 100644
--- a/scene/resources/default_theme/icon_zoom_less.png
+++ b/scene/resources/default_theme/icon_zoom_less.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_zoom_more.png b/scene/resources/default_theme/icon_zoom_more.png
index fa675045bc..31467ec3de 100644
--- a/scene/resources/default_theme/icon_zoom_more.png
+++ b/scene/resources/default_theme/icon_zoom_more.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_zoom_reset.png b/scene/resources/default_theme/icon_zoom_reset.png
index 953ae47d24..cac68c09fa 100644
--- a/scene/resources/default_theme/icon_zoom_reset.png
+++ b/scene/resources/default_theme/icon_zoom_reset.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit.png b/scene/resources/default_theme/line_edit.png
index bf2b91f1be..2b0c506f34 100644
--- a/scene/resources/default_theme/line_edit.png
+++ b/scene/resources/default_theme/line_edit.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit_clear.png b/scene/resources/default_theme/line_edit_clear.png
new file mode 100644
index 0000000000..af2775a132
--- /dev/null
+++ b/scene/resources/default_theme/line_edit_clear.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit_disabled.png b/scene/resources/default_theme/line_edit_disabled.png
index a0fa505e4c..69d78febd9 100644
--- a/scene/resources/default_theme/line_edit_disabled.png
+++ b/scene/resources/default_theme/line_edit_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit_focus.png b/scene/resources/default_theme/line_edit_focus.png
index e66d7b60e3..1d74b74068 100644
--- a/scene/resources/default_theme/line_edit_focus.png
+++ b/scene/resources/default_theme/line_edit_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/logo.png b/scene/resources/default_theme/logo.png
index 2161402438..d0ef9d8aa7 100644
--- a/scene/resources/default_theme/logo.png
+++ b/scene/resources/default_theme/logo.png
Binary files differ
diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py
index db449f9417..73b1ae0b0b 100755
--- a/scene/resources/default_theme/make_header.py
+++ b/scene/resources/default_theme/make_header.py
@@ -4,15 +4,16 @@ import os
import glob
import string
+enc = "utf-8"
# Generate include files
f = open("theme_data.h", "wb")
-f.write("// THIS FILE HAS BEEN AUTOGENERATED, DON'T EDIT!!\n")
+f.write(b"// THIS FILE HAS BEEN AUTOGENERATED, DON\'T EDIT!!\n")
# Generate png image block
-f.write("\n// png image block\n");
+f.write(b"\n// png image block\n")
pixmaps = glob.glob("*.png")
pixmaps.sort()
@@ -21,22 +22,23 @@ for x in pixmaps:
var_str = x[:-4] + "_png"
- f.write("\nstatic const unsigned char " + var_str + "[] = {\n\t")
+ s = "\nstatic const unsigned char " + var_str + "[] = {\n\t"
+ f.write(s.encode(enc))
pngf = open(x, "rb")
b = pngf.read(1)
while(len(b) == 1):
- f.write(hex(ord(b)))
+ f.write(hex(ord(b)).encode(enc))
b = pngf.read(1)
if (len(b) == 1):
- f.write(", ")
+ f.write(b", ")
- f.write("\n};\n")
+ f.write(b"\n};\n")
pngf.close()
# Generate shaders block
-f.write("\n// shaders block\n");
+f.write(b"\n// shaders block\n");
shaders = glob.glob("*.gsl")
shaders.sort()
@@ -45,7 +47,8 @@ for x in shaders:
var_str = x[:-4] + "_shader_code"
- f.write("\nstatic const char *" + var_str + " = \n")
+ s = "\nstatic const char *" + var_str + " = \n"
+ f.write(s.encode(enc))
sf = open(x, "rb")
@@ -55,12 +58,13 @@ for x in shaders:
b = b[:-2]
if (b.endswith("\n")):
b = b[:-1]
- f.write(" \"" + b)
+ s = ' \"' + b
+ f.write(s.encode(enc))
b = sf.readline()
if (b != ""):
- f.write("\"\n")
+ f.write(b'"\n')
- f.write("\";\n")
+ f.write(b'";\n')
sf.close()
f.close()
diff --git a/scene/resources/default_theme/mini_checkerboard.png b/scene/resources/default_theme/mini_checkerboard.png
index 3e53183847..d8279bda80 100644
--- a/scene/resources/default_theme/mini_checkerboard.png
+++ b/scene/resources/default_theme/mini_checkerboard.png
Binary files differ
diff --git a/scene/resources/default_theme/option_arrow.png b/scene/resources/default_theme/option_arrow.png
index 007de16bfa..40590fd60a 100644
--- a/scene/resources/default_theme/option_arrow.png
+++ b/scene/resources/default_theme/option_arrow.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_disabled.png b/scene/resources/default_theme/option_button_disabled.png
index ce727d56e1..1961b673cd 100644
--- a/scene/resources/default_theme/option_button_disabled.png
+++ b/scene/resources/default_theme/option_button_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_focus.png b/scene/resources/default_theme/option_button_focus.png
index c76d91287e..402670f9a2 100644
--- a/scene/resources/default_theme/option_button_focus.png
+++ b/scene/resources/default_theme/option_button_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_hover.png b/scene/resources/default_theme/option_button_hover.png
index fd1e987ceb..826fe1c9ca 100644
--- a/scene/resources/default_theme/option_button_hover.png
+++ b/scene/resources/default_theme/option_button_hover.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png
index 9d7fb98d1c..2dadb40338 100644
--- a/scene/resources/default_theme/option_button_normal.png
+++ b/scene/resources/default_theme/option_button_normal.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_pressed.png b/scene/resources/default_theme/option_button_pressed.png
index 28b1d93468..68796f9d85 100644
--- a/scene/resources/default_theme/option_button_pressed.png
+++ b/scene/resources/default_theme/option_button_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/panel_bg.png b/scene/resources/default_theme/panel_bg.png
index 320819ad6d..b496e2177e 100644
--- a/scene/resources/default_theme/panel_bg.png
+++ b/scene/resources/default_theme/panel_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_bg.png b/scene/resources/default_theme/popup_bg.png
index 63f5994441..023029f936 100644
--- a/scene/resources/default_theme/popup_bg.png
+++ b/scene/resources/default_theme/popup_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_bg_disabled.png b/scene/resources/default_theme/popup_bg_disabled.png
index 611d949380..8eab5f27bc 100644
--- a/scene/resources/default_theme/popup_bg_disabled.png
+++ b/scene/resources/default_theme/popup_bg_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_checked.png b/scene/resources/default_theme/popup_checked.png
index a24e0543c0..b7b05640e1 100644
--- a/scene/resources/default_theme/popup_checked.png
+++ b/scene/resources/default_theme/popup_checked.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_hover.png b/scene/resources/default_theme/popup_hover.png
index 85d4e48475..bdb6ae8bd0 100644
--- a/scene/resources/default_theme/popup_hover.png
+++ b/scene/resources/default_theme/popup_hover.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_unchecked.png b/scene/resources/default_theme/popup_unchecked.png
index c1137e6fbf..ff922335c3 100644
--- a/scene/resources/default_theme/popup_unchecked.png
+++ b/scene/resources/default_theme/popup_unchecked.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_window.png b/scene/resources/default_theme/popup_window.png
index 59362a8ffd..174a29ef45 100644
--- a/scene/resources/default_theme/popup_window.png
+++ b/scene/resources/default_theme/popup_window.png
Binary files differ
diff --git a/scene/resources/default_theme/progress_bar.png b/scene/resources/default_theme/progress_bar.png
index bf81e3adea..057557e567 100644
--- a/scene/resources/default_theme/progress_bar.png
+++ b/scene/resources/default_theme/progress_bar.png
Binary files differ
diff --git a/scene/resources/default_theme/progress_fill.png b/scene/resources/default_theme/progress_fill.png
index 3a34dfdda6..e39bb2a021 100644
--- a/scene/resources/default_theme/progress_fill.png
+++ b/scene/resources/default_theme/progress_fill.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_checked.png b/scene/resources/default_theme/radio_checked.png
index 95d472022f..0ce575c15f 100644
--- a/scene/resources/default_theme/radio_checked.png
+++ b/scene/resources/default_theme/radio_checked.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_unchecked.png b/scene/resources/default_theme/radio_unchecked.png
index 7f0535c3a4..fe5bcf6ab1 100644
--- a/scene/resources/default_theme/radio_unchecked.png
+++ b/scene/resources/default_theme/radio_unchecked.png
Binary files differ
diff --git a/scene/resources/default_theme/reference_border.png b/scene/resources/default_theme/reference_border.png
index 96219676bf..6a680f393c 100644
--- a/scene/resources/default_theme/reference_border.png
+++ b/scene/resources/default_theme/reference_border.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_bg.png b/scene/resources/default_theme/scroll_bg.png
index cefadb2c08..fb151a48b1 100644
--- a/scene/resources/default_theme/scroll_bg.png
+++ b/scene/resources/default_theme/scroll_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_down.png b/scene/resources/default_theme/scroll_button_down.png
index caeac9b286..1df4ef5b6b 100644
--- a/scene/resources/default_theme/scroll_button_down.png
+++ b/scene/resources/default_theme/scroll_button_down.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_down_hl.png b/scene/resources/default_theme/scroll_button_down_hl.png
index 48036e0297..ba79087393 100644
--- a/scene/resources/default_theme/scroll_button_down_hl.png
+++ b/scene/resources/default_theme/scroll_button_down_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_left.png b/scene/resources/default_theme/scroll_button_left.png
index 3b50938d97..e430cb4673 100644
--- a/scene/resources/default_theme/scroll_button_left.png
+++ b/scene/resources/default_theme/scroll_button_left.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_left_hl.png b/scene/resources/default_theme/scroll_button_left_hl.png
index b3d348c24f..2a6ef17a34 100644
--- a/scene/resources/default_theme/scroll_button_left_hl.png
+++ b/scene/resources/default_theme/scroll_button_left_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_right.png b/scene/resources/default_theme/scroll_button_right.png
index 1c622a41ad..4f61687aa4 100644
--- a/scene/resources/default_theme/scroll_button_right.png
+++ b/scene/resources/default_theme/scroll_button_right.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_right_hl.png b/scene/resources/default_theme/scroll_button_right_hl.png
index 108796ca02..10e2722509 100644
--- a/scene/resources/default_theme/scroll_button_right_hl.png
+++ b/scene/resources/default_theme/scroll_button_right_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_up.png b/scene/resources/default_theme/scroll_button_up.png
index 2c8238ae4c..f425412f50 100644
--- a/scene/resources/default_theme/scroll_button_up.png
+++ b/scene/resources/default_theme/scroll_button_up.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_button_up_hl.png b/scene/resources/default_theme/scroll_button_up_hl.png
index 4283bd114a..615a236c52 100644
--- a/scene/resources/default_theme/scroll_button_up_hl.png
+++ b/scene/resources/default_theme/scroll_button_up_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber.png b/scene/resources/default_theme/scroll_grabber.png
index 1d625a9b7b..732725a28f 100644
--- a/scene/resources/default_theme/scroll_grabber.png
+++ b/scene/resources/default_theme/scroll_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png
index 99eb24b7e7..006cfa3361 100644
--- a/scene/resources/default_theme/scroll_grabber_hl.png
+++ b/scene/resources/default_theme/scroll_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber_pressed.png b/scene/resources/default_theme/scroll_grabber_pressed.png
index a46d242ddd..f4886158fa 100644
--- a/scene/resources/default_theme/scroll_grabber_pressed.png
+++ b/scene/resources/default_theme/scroll_grabber_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/selection.png b/scene/resources/default_theme/selection.png
index 501877a8b4..7d1c985b35 100644
--- a/scene/resources/default_theme/selection.png
+++ b/scene/resources/default_theme/selection.png
Binary files differ
diff --git a/scene/resources/default_theme/selection_oof.png b/scene/resources/default_theme/selection_oof.png
index 9594fe0913..2da0538389 100644
--- a/scene/resources/default_theme/selection_oof.png
+++ b/scene/resources/default_theme/selection_oof.png
Binary files differ
diff --git a/scene/resources/default_theme/spinbox_updown.png b/scene/resources/default_theme/spinbox_updown.png
index b40b1e9fd2..74fab19f34 100644
--- a/scene/resources/default_theme/spinbox_updown.png
+++ b/scene/resources/default_theme/spinbox_updown.png
Binary files differ
diff --git a/scene/resources/default_theme/submenu.png b/scene/resources/default_theme/submenu.png
index ec727eecf1..8f7de446d4 100644
--- a/scene/resources/default_theme/submenu.png
+++ b/scene/resources/default_theme/submenu.png
Binary files differ
diff --git a/scene/resources/default_theme/tab.png b/scene/resources/default_theme/tab.png
index 3e4d792a48..895daa65e2 100644
--- a/scene/resources/default_theme/tab.png
+++ b/scene/resources/default_theme/tab.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_behind.png b/scene/resources/default_theme/tab_behind.png
index 12f07c3a91..2803d9db65 100644
--- a/scene/resources/default_theme/tab_behind.png
+++ b/scene/resources/default_theme/tab_behind.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_close.png b/scene/resources/default_theme/tab_close.png
index 20d9b5c810..af2775a132 100644
--- a/scene/resources/default_theme/tab_close.png
+++ b/scene/resources/default_theme/tab_close.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png
index 92482aaf28..7d0bd16221 100644
--- a/scene/resources/default_theme/tab_container_bg.png
+++ b/scene/resources/default_theme/tab_container_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png
index 7289e032da..520d147217 100644
--- a/scene/resources/default_theme/tab_current.png
+++ b/scene/resources/default_theme/tab_current.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_menu.png b/scene/resources/default_theme/tab_menu.png
index 148b64b8aa..fa4421a28a 100644
--- a/scene/resources/default_theme/tab_menu.png
+++ b/scene/resources/default_theme/tab_menu.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_menu_hl.png b/scene/resources/default_theme/tab_menu_hl.png
index 148b64b8aa..fa4421a28a 100644
--- a/scene/resources/default_theme/tab_menu_hl.png
+++ b/scene/resources/default_theme/tab_menu_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index c6b37cad5a..353e7eddbe 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -3,35 +3,35 @@
// png image block
static const unsigned char arrow_down_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6d, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0x63, 0x60, 0x18, 0x74, 0x80, 0x11, 0xc6, 0x78, 0xf0, 0xe0, 0xc1, 0x7f, 0x7c, 0xa, 0x15, 0x14, 0x14, 0x18, 0x19, 0x18, 0x18, 0x18, 0x98, 0x48, 0xb5, 0x81, 0x7c, 0xd, 0x8c, 0x8c, 0x8c, 0xf1, 0xc, 0xc, 0xc, 0x5f, 0xb1, 0xa8, 0xf9, 0xce, 0xc8, 0xc8, 0x98, 0xe, 0x57, 0x87, 0x2c, 0x73, 0xff, 0xfe, 0x7d, 0xd, 0x6, 0x6, 0x86, 0x55, 0x8c, 0x8c, 0x8c, 0xba, 0x50, 0xa1, 0x1b, 0xcc, 0xcc, 0xcc, 0x61, 0xb2, 0xb2, 0xb2, 0x97, 0xb1, 0x6a, 0x60, 0x60, 0x60, 0x60, 0x78, 0xf1, 0xe2, 0x5, 0xf7, 0xcf, 0x9f, 0x3f, 0xa7, 0x30, 0x30, 0x30, 0x30, 0xb0, 0xb3, 0xb3, 0xe7, 0x48, 0x48, 0x48, 0x60, 0xb3, 0x75, 0x30, 0x1, 0x0, 0x28, 0x20, 0x14, 0xc2, 0x1b, 0xd0, 0x7c, 0xca, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x34, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x32, 0x78, 0xf0, 0x1f, 0x15, 0x52, 0x20, 0xf1, 0x30, 0xee, 0xc1, 0x17, 0xb8, 0xf0, 0xb7, 0x87, 0x69, 0x48, 0xb6, 0xdc, 0xd7, 0xb8, 0x7f, 0x9, 0x2c, 0x7c, 0xfd, 0xb1, 0x2e, 0x9a, 0x3, 0x5e, 0x70, 0x3f, 0x9c, 0xff, 0x70, 0xfe, 0xb, 0x6e, 0x6, 0xea, 0x3, 0x0, 0xfb, 0x81, 0x48, 0xb8, 0x4d, 0xe4, 0x75, 0xd9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char arrow_right_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6c, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0x63, 0x60, 0xa0, 0x35, 0x60, 0x44, 0xe6, 0x3c, 0x78, 0xf0, 0xe0, 0x3f, 0x8c, 0xfd, 0xff, 0xff, 0xff, 0x44, 0x45, 0x45, 0xc5, 0x5, 0xe8, 0x1a, 0x98, 0x70, 0x9a, 0xc4, 0xc8, 0x38, 0xe5, 0xe1, 0xc3, 0x87, 0xda, 0x44, 0x6b, 0x60, 0x60, 0x60, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xaa, 0x17, 0x2f, 0x5e, 0x70, 0x13, 0xab, 0x81, 0x81, 0x81, 0x81, 0x41, 0xeb, 0xe7, 0xcf, 0x9f, 0x53, 0x48, 0xd1, 0x80, 0x1, 0x8, 0x69, 0xb8, 0xc6, 0xce, 0xce, 0x9e, 0x43, 0xac, 0x86, 0xaf, 0x8c, 0x8c, 0x8c, 0x61, 0x12, 0x12, 0x12, 0x5f, 0x89, 0xd2, 0xf0, 0xff, 0xff, 0xff, 0x1c, 0x79, 0x79, 0xf9, 0xab, 0x84, 0x1d, 0x49, 0x6d, 0x0, 0x0, 0x8f, 0x30, 0x1e, 0x10, 0x6e, 0x79, 0xda, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char background_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x44, 0xa4, 0x8a, 0xc6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x11, 0x50, 0x4c, 0x54, 0x45, 0x91, 0xc9, 0xab, 0x90, 0xc9, 0xab, 0x90, 0xc9, 0xaa, 0x90, 0xc8, 0xab, 0x91, 0xc9, 0xaa, 0x91, 0xc8, 0xab, 0x90, 0xc8, 0xaa, 0x8f, 0xc8, 0xab, 0x8f, 0xc9, 0xab, 0x8f, 0xc8, 0xaa, 0x90, 0xc7, 0xaa, 0x90, 0xc7, 0xab, 0x8f, 0xc7, 0xaa, 0x8f, 0xc7, 0xab, 0x8e, 0xc7, 0xab, 0x8e, 0xc6, 0xab, 0x8f, 0xc6, 0xab, 0x8e, 0xc6, 0xaa, 0x8f, 0xc6, 0xaa, 0x8e, 0xc7, 0xaa, 0x8e, 0xc5, 0xaa, 0x8e, 0xc5, 0xab, 0x8d, 0xc5, 0xaa, 0x8d, 0xc5, 0xab, 0x8d, 0xc6, 0xaa, 0x8d, 0xc6, 0xab, 0x8d, 0xc4, 0xaa, 0x8e, 0xc4, 0xab, 0x8d, 0xc4, 0xab, 0x8e, 0xc4, 0xaa, 0x8c, 0xc4, 0xaa, 0x8c, 0xc5, 0xaa, 0x8d, 0xc3, 0xab, 0x8d, 0xc3, 0xaa, 0x8c, 0xc3, 0xaa, 0x8c, 0xc4, 0xab, 0x8c, 0xc3, 0xab, 0x8c, 0xc2, 0xab, 0x8b, 0xc2, 0xaa, 0x8b, 0xc3, 0xaa, 0x8b, 0xc3, 0xab, 0x8c, 0xc2, 0xaa, 0x8b, 0xc2, 0xab, 0x8b, 0xc1, 0xaa, 0x8b, 0xc1, 0xab, 0x8a, 0xc2, 0xaa, 0x8a, 0xc1, 0xaa, 0x8a, 0xc0, 0xaa, 0x8b, 0xc0, 0xaa, 0x8a, 0xc1, 0xa9, 0x8a, 0xc0, 0xa9, 0x89, 0xc0, 0xaa, 0x8a, 0xbf, 0xaa, 0x89, 0xbf, 0xaa, 0x89, 0xbf, 0xa9, 0x8a, 0xbf, 0xa9, 0x88, 0xbf, 0xaa, 0x89, 0xbe, 0xaa, 0x89, 0xbe, 0xa9, 0x88, 0xbf, 0xa9, 0x88, 0xbe, 0xa9, 0x88, 0xbe, 0xaa, 0x88, 0xbd, 0xaa, 0x88, 0xbd, 0xa9, 0x89, 0xbd, 0xaa, 0x89, 0xbd, 0xa9, 0x87, 0xbe, 0xa9, 0x87, 0xbd, 0xaa, 0x87, 0xbe, 0xaa, 0x87, 0xbd, 0xa9, 0x87, 0xbc, 0xaa, 0x88, 0xbc, 0xa9, 0x88, 0xbc, 0xaa, 0x87, 0xbc, 0xa9, 0x86, 0xbc, 0xa9, 0x87, 0xbb, 0xaa, 0x87, 0xbb, 0xa9, 0x86, 0xbb, 0xa9, 0x86, 0xbc, 0xaa, 0x86, 0xbb, 0xaa, 0x86, 0xba, 0xaa, 0x86, 0xba, 0xa9, 0x85, 0xba, 0xa9, 0x85, 0xbb, 0xaa, 0x85, 0xbb, 0xa9, 0x85, 0xba, 0xaa, 0x85, 0xb9, 0xa9, 0x86, 0xb9, 0xa9, 0x86, 0xb9, 0xaa, 0x85, 0xb9, 0xaa, 0xff, 0xff, 0xff, 0x25, 0xe, 0xc5, 0xe1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x5a, 0x3, 0xbb, 0xa5, 0xa2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x2, 0xaa, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x45, 0x4b, 0xd, 0x63, 0x9a, 0x56, 0x14, 0xbd, 0x86, 0x2d, 0x24, 0x2b, 0xf8, 0x8a, 0x1, 0xcc, 0x18, 0x23, 0xcd, 0x8b, 0xc5, 0x2a, 0xa9, 0x6e, 0x51, 0x98, 0x58, 0x3e, 0xda, 0x52, 0x69, 0x9e, 0x4a, 0x10, 0xba, 0xb8, 0xec, 0xff, 0xff, 0x91, 0x9d, 0x47, 0xd2, 0xf5, 0xbc, 0xcb, 0x3d, 0x1f, 0xf7, 0x40, 0xd4, 0x23, 0x4c, 0x4f, 0x2, 0x9b, 0xa8, 0x93, 0x27, 0x9d, 0xa3, 0xe7, 0x50, 0xe9, 0xc9, 0x79, 0x69, 0x74, 0xf7, 0x9f, 0x7a, 0x8a, 0xd2, 0xfb, 0xf9, 0xf4, 0x25, 0x53, 0xd5, 0x33, 0xf4, 0xcf, 0xce, 0x90, 0x9d, 0xa8, 0xa, 0x80, 0x75, 0xaa, 0xc8, 0xca, 0xa9, 0xa2, 0x9c, 0xf4, 0x54, 0x52, 0x91, 0x9c, 0xab, 0x2a, 0x46, 0x42, 0xf9, 0xe5, 0xb4, 0x2b, 0xa9, 0xe7, 0xca, 0xab, 0x57, 0xc8, 0x15, 0x8d, 0x74, 0x4d, 0xd5, 0x25, 0x40, 0x8a, 0xae, 0xea, 0xda, 0xb9, 0xd6, 0x59, 0x55, 0x12, 0xfe, 0xd0, 0x49, 0xef, 0xb3, 0xbe, 0xfe, 0x5a, 0x37, 0x34, 0x66, 0x30, 0x5d, 0xd3, 0xfb, 0xfa, 0x80, 0x69, 0x3, 0x7d, 0x70, 0xd1, 0xd5, 0xfa, 0x9a, 0x4e, 0x3, 0xe3, 0x62, 0xd0, 0xd7, 0xd, 0xd6, 0x37, 0x98, 0xd1, 0xef, 0xf, 0xc0, 0x9a, 0xc1, 0x2e, 0xc, 0xc6, 0x2e, 0xd8, 0xeb, 0x1, 0x86, 0x98, 0x61, 0x32, 0x13, 0x7f, 0x33, 0x66, 0x49, 0x36, 0xba, 0x41, 0x68, 0x18, 0xdd, 0x66, 0x64, 0x5b, 0x96, 0x69, 0x59, 0x90, 0xd6, 0xf0, 0x72, 0x68, 0x9a, 0x43, 0xd3, 0xfa, 0xd5, 0x32, 0x2f, 0x6d, 0xe3, 0xd2, 0xb2, 0x98, 0x65, 0x30, 0x93, 0x1c, 0x7b, 0x88, 0x67, 0xdb, 0xa6, 0xd, 0x72, 0x7e, 0x1b, 0xba, 0xa8, 0xc0, 0xda, 0xbf, 0xf, 0x91, 0xba, 0xb6, 0x4b, 0x8e, 0xe7, 0x78, 0xee, 0xd0, 0x75, 0x87, 0x1e, 0xac, 0xe3, 0x60, 0x5f, 0x39, 0x57, 0xe, 0x84, 0xe7, 0xd8, 0xb6, 0x63, 0x5f, 0xd1, 0x1b, 0xe7, 0x9a, 0xcb, 0x92, 0xe7, 0xba, 0xae, 0xe7, 0xf0, 0x1b, 0xc7, 0xb9, 0x76, 0x3c, 0x8e, 0xb3, 0x87, 0x16, 0xbf, 0xf1, 0x88, 0x73, 0xee, 0x8c, 0x46, 0xd8, 0xd7, 0x7c, 0xe4, 0xf1, 0xef, 0x18, 0x79, 0x37, 0x9c, 0x7b, 0x6f, 0xbc, 0x11, 0x27, 0xfe, 0xd6, 0xf7, 0xf9, 0x98, 0xf3, 0x77, 0x13, 0xfe, 0x96, 0x8f, 0xb8, 0x3f, 0x96, 0x65, 0x9f, 0x4f, 0x38, 0x1f, 0x4f, 0xf8, 0x68, 0xc2, 0xc9, 0x7f, 0xc6, 0x74, 0xea, 0x73, 0x49, 0x13, 0xcc, 0x78, 0xe2, 0xfb, 0x13, 0x59, 0xf2, 0xdf, 0xf9, 0x63, 0xa, 0xa6, 0xfe, 0x34, 0xf0, 0xf1, 0xba, 0xe9, 0x20, 0x39, 0xf0, 0x6f, 0x83, 0xdb, 0x69, 0x10, 0x4c, 0x29, 0x78, 0x3f, 0xb, 0x50, 0x91, 0xe7, 0xc0, 0x9f, 0x61, 0xdd, 0x6, 0xb3, 0xd9, 0xcc, 0xf7, 0xdf, 0x83, 0xe0, 0x2, 0x9a, 0xcd, 0x67, 0xcf, 0x98, 0x77, 0xea, 0xf, 0x29, 0xe4, 0xfc, 0x9, 0x13, 0x40, 0xd0, 0x1c, 0x87, 0x1f, 0xb8, 0x93, 0xab, 0xb, 0xee, 0x5e, 0x62, 0x5a, 0x2c, 0xe7, 0x21, 0x78, 0xb9, 0x58, 0x2e, 0xb1, 0xd1, 0xb8, 0x5b, 0x84, 0x4b, 0xd8, 0xf9, 0x7c, 0x81, 0xef, 0x2e, 0xa4, 0xc5, 0x22, 0xc, 0x97, 0x61, 0x18, 0x85, 0x12, 0x51, 0x4, 0x5e, 0x46, 0x61, 0xf4, 0x97, 0x74, 0xb, 0xb9, 0xa8, 0x3b, 0xad, 0xe2, 0x38, 0xa, 0xd7, 0xab, 0x28, 0x4, 0x85, 0x1f, 0xe2, 0x10, 0x1c, 0xc5, 0xe1, 0x2a, 0x5c, 0x25, 0x2b, 0x4a, 0xe3, 0x38, 0x49, 0x93, 0x24, 0x4d, 0xe3, 0x34, 0x4e, 0xe2, 0x68, 0xd, 0x1f, 0xad, 0x93, 0x24, 0x59, 0x23, 0xfa, 0xb0, 0x4e, 0x53, 0xca, 0xf2, 0x2c, 0xfb, 0xf8, 0xf1, 0x13, 0x6c, 0x92, 0x42, 0xa7, 0x49, 0x9e, 0xe6, 0x69, 0x92, 0x49, 0xd3, 0x65, 0x94, 0x7d, 0xce, 0xb2, 0x2c, 0xc9, 0xd2, 0xa2, 0xf8, 0x92, 0xe7, 0x59, 0x51, 0xc0, 0x7d, 0xce, 0xb, 0xc8, 0x1c, 0xc8, 0x36, 0x5, 0x95, 0x5f, 0xb3, 0x72, 0x53, 0x66, 0xf7, 0x5f, 0x37, 0x70, 0xf7, 0x79, 0x51, 0x88, 0xfb, 0x12, 0x3d, 0x91, 0xdd, 0x8b, 0x4d, 0x99, 0x8b, 0x92, 0x44, 0x59, 0xa, 0x51, 0x8a, 0x72, 0xb, 0x2e, 0x37, 0x2, 0x1a, 0xa2, 0x0, 0x8b, 0xd, 0x62, 0x21, 0x48, 0xec, 0x76, 0x7b, 0x21, 0xaa, 0x52, 0xec, 0xb6, 0xa2, 0xaa, 0xb6, 0xf, 0xfb, 0x7d, 0x2d, 0xc4, 0xf6, 0xa1, 0x7a, 0x10, 0xdb, 0x9d, 0x28, 0x77, 0x15, 0x55, 0xbb, 0xba, 0x92, 0xd8, 0x57, 0xbb, 0xaa, 0xaa, 0xeb, 0x7d, 0x2d, 0xed, 0xff, 0xdf, 0xbe, 0xa6, 0x43, 0xd5, 0x34, 0x75, 0xd3, 0x54, 0xcd, 0xa1, 0xaa, 0xf, 0x75, 0x83, 0xbc, 0xae, 0x5a, 0xb4, 0x64, 0xf6, 0xd, 0x1d, 0x6a, 0x25, 0x9a, 0xa6, 0x6d, 0xab, 0x43, 0x3, 0xfc, 0x2d, 0x57, 0x8b, 0xf7, 0xf8, 0xd8, 0xb4, 0x87, 0xb6, 0x6e, 0xe9, 0xb1, 0x6d, 0x8e, 0x6d, 0x7b, 0x6c, 0xff, 0x39, 0x3e, 0x1d, 0x9f, 0x20, 0x8f, 0xd2, 0x1d, 0xff, 0x45, 0xa, 0xdd, 0xb6, 0x4f, 0xff, 0x1, 0xbe, 0xd3, 0xa6, 0xf7, 0x55, 0x9e, 0xe1, 0xf0, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x44, 0xa4, 0x8a, 0xc6, 0x0, 0x0, 0x1, 0xe, 0x50, 0x4c, 0x54, 0x45, 0x91, 0xc9, 0xab, 0x90, 0xc9, 0xab, 0x90, 0xc9, 0xaa, 0x90, 0xc8, 0xab, 0x91, 0xc9, 0xaa, 0x91, 0xc8, 0xab, 0x90, 0xc8, 0xaa, 0x8f, 0xc8, 0xab, 0x8f, 0xc9, 0xab, 0x8f, 0xc8, 0xaa, 0x90, 0xc7, 0xaa, 0x90, 0xc7, 0xab, 0x8f, 0xc7, 0xaa, 0x8f, 0xc7, 0xab, 0x8e, 0xc7, 0xab, 0x8e, 0xc6, 0xab, 0x8f, 0xc6, 0xab, 0x8e, 0xc6, 0xaa, 0x8f, 0xc6, 0xaa, 0x8e, 0xc7, 0xaa, 0x8e, 0xc5, 0xaa, 0x8e, 0xc5, 0xab, 0x8d, 0xc5, 0xaa, 0x8d, 0xc5, 0xab, 0x8d, 0xc6, 0xaa, 0x8d, 0xc6, 0xab, 0x8d, 0xc4, 0xaa, 0x8e, 0xc4, 0xab, 0x8d, 0xc4, 0xab, 0x8e, 0xc4, 0xaa, 0x8c, 0xc4, 0xaa, 0x8c, 0xc5, 0xaa, 0x8d, 0xc3, 0xab, 0x8d, 0xc3, 0xaa, 0x8c, 0xc3, 0xaa, 0x8c, 0xc4, 0xab, 0x8c, 0xc3, 0xab, 0x8c, 0xc2, 0xab, 0x8b, 0xc2, 0xaa, 0x8b, 0xc3, 0xaa, 0x8b, 0xc3, 0xab, 0x8c, 0xc2, 0xaa, 0x8b, 0xc2, 0xab, 0x8b, 0xc1, 0xaa, 0x8b, 0xc1, 0xab, 0x8a, 0xc2, 0xaa, 0x8a, 0xc1, 0xaa, 0x8a, 0xc0, 0xaa, 0x8b, 0xc0, 0xaa, 0x8a, 0xc1, 0xa9, 0x8a, 0xc0, 0xa9, 0x89, 0xc0, 0xaa, 0x8a, 0xbf, 0xaa, 0x89, 0xbf, 0xaa, 0x89, 0xbf, 0xa9, 0x8a, 0xbf, 0xa9, 0x88, 0xbf, 0xaa, 0x89, 0xbe, 0xaa, 0x89, 0xbe, 0xa9, 0x88, 0xbf, 0xa9, 0x88, 0xbe, 0xa9, 0x88, 0xbe, 0xaa, 0x88, 0xbd, 0xaa, 0x88, 0xbd, 0xa9, 0x89, 0xbd, 0xaa, 0x89, 0xbd, 0xa9, 0x87, 0xbe, 0xa9, 0x87, 0xbd, 0xaa, 0x87, 0xbe, 0xaa, 0x87, 0xbd, 0xa9, 0x87, 0xbc, 0xaa, 0x88, 0xbc, 0xa9, 0x88, 0xbc, 0xaa, 0x87, 0xbc, 0xa9, 0x86, 0xbc, 0xa9, 0x87, 0xbb, 0xaa, 0x87, 0xbb, 0xa9, 0x86, 0xbb, 0xa9, 0x86, 0xbc, 0xaa, 0x86, 0xbb, 0xaa, 0x86, 0xba, 0xaa, 0x86, 0xba, 0xa9, 0x85, 0xba, 0xa9, 0x85, 0xbb, 0xaa, 0x85, 0xbb, 0xa9, 0x85, 0xba, 0xaa, 0x85, 0xb9, 0xa9, 0x86, 0xb9, 0xa9, 0x86, 0xb9, 0xaa, 0x85, 0xb9, 0xaa, 0x3e, 0xa0, 0x4f, 0x4f, 0x0, 0x0, 0x2, 0x3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2d, 0x4a, 0x7, 0x82, 0x4, 0x37, 0x12, 0x2, 0xa, 0x4a, 0xea, 0x9e, 0xbd, 0xff, 0x3f, 0xf5, 0x6c, 0x4f, 0x4b, 0xda, 0x58, 0x91, 0x24, 0x10, 0x20, 0xf8, 0x5d, 0x20, 0x81, 0x1f, 0xa8, 0x1f, 0xf6, 0x7, 0xf5, 0x7d, 0x0, 0x0, 0x3c, 0x0, 0x8, 0x14, 0x28, 0xb8, 0x41, 0x0, 0x50, 0x7b, 0x70, 0x63, 0xc, 0x9, 0x1c, 0xaa, 0x52, 0xeb, 0x4, 0x5b, 0xfb, 0x1d, 0x89, 0x68, 0xe1, 0x39, 0x9c, 0x7d, 0x68, 0x77, 0x60, 0x8c, 0x7a, 0x80, 0xe5, 0x6e, 0xdc, 0x41, 0x47, 0x51, 0x5f, 0xb8, 0xdd, 0xed, 0xa0, 0x9f, 0xc6, 0xad, 0xba, 0xee, 0xfb, 0xee, 0xde, 0x97, 0x74, 0x6f, 0x98, 0x82, 0x26, 0x51, 0x30, 0xa6, 0x3f, 0x10, 0xc8, 0xad, 0x13, 0xe4, 0x83, 0x0, 0x7a, 0x4, 0x4a, 0xd9, 0x5c, 0xde, 0xd2, 0x16, 0x15, 0xf2, 0xac, 0xac, 0x3e, 0x8f, 0x5a, 0x15, 0x3a, 0x5a, 0xe0, 0x6a, 0x1, 0xdc, 0xbd, 0x9b, 0x47, 0x44, 0xb6, 0x1e, 0x44, 0x5b, 0xe7, 0x84, 0x4b, 0xc3, 0xc, 0x1b, 0x51, 0xeb, 0xaa, 0x54, 0xc7, 0xb3, 0xeb, 0xca, 0x1a, 0x36, 0xbc, 0x76, 0x64, 0x4a, 0x62, 0x54, 0x3c, 0xe7, 0xf4, 0xc0, 0xd4, 0x1b, 0xda, 0x48, 0xa4, 0xc1, 0xd7, 0x98, 0xc2, 0xac, 0x19, 0x76, 0xd7, 0x44, 0x80, 0x33, 0xfe, 0xcb, 0x2b, 0x97, 0x6d, 0x8e, 0x2, 0x36, 0x4a, 0xfd, 0xc, 0xef, 0xb1, 0x35, 0x76, 0x63, 0x62, 0xc6, 0x5b, 0x38, 0xd3, 0x7e, 0x0, 0x7b, 0xfe, 0xef, 0x48, 0x93, 0xff, 0xdc, 0x3d, 0xed, 0xf4, 0xc4, 0xc4, 0x99, 0x93, 0xd3, 0x68, 0x5c, 0x9e, 0xee, 0x87, 0x16, 0xca, 0x1f, 0xbb, 0x80, 0x9e, 0xa0, 0x5, 0x47, 0x0, 0xbc, 0x5f, 0x7, 0x79, 0xa9, 0x3, 0x99, 0x80, 0x8f, 0xa7, 0x16, 0x68, 0xcd, 0x3a, 0x3d, 0x32, 0x60, 0xc0, 0x6f, 0xd8, 0x2b, 0x8a, 0xe1, 0x20, 0xf, 0xe3, 0x4, 0xcf, 0xfa, 0x1a, 0xb, 0x90, 0xfb, 0x2a, 0x57, 0x4a, 0xa8, 0xc9, 0xb7, 0x91, 0x37, 0x82, 0xf7, 0x4c, 0xd2, 0xa9, 0x9a, 0x78, 0x8f, 0x53, 0x22, 0x40, 0xfd, 0x44, 0x5c, 0xdf, 0xeb, 0x89, 0x4a, 0xc9, 0x0, 0xe7, 0x74, 0x1, 0x28, 0xff, 0xa6, 0x7e, 0xa, 0x4, 0xe9, 0x43, 0xe2, 0x7, 0x7d, 0xaf, 0x9, 0xca, 0x61, 0x3, 0x88, 0x13, 0x20, 0xab, 0x50, 0x1e, 0x41, 0xbc, 0x68, 0x3, 0xd5, 0xc2, 0x69, 0xa4, 0x5b, 0x22, 0xbb, 0x35, 0xdc, 0x45, 0x72, 0x94, 0xba, 0x85, 0xee, 0x82, 0x54, 0x0, 0xcb, 0x45, 0xa4, 0x78, 0xa, 0xc0, 0x28, 0x1c, 0x91, 0x46, 0x50, 0xa3, 0x34, 0xcb, 0x63, 0xfa, 0xeb, 0xb8, 0xd8, 0x5e, 0x9e, 0xde, 0x2b, 0xa3, 0xda, 0x35, 0xd3, 0x62, 0xc4, 0x8e, 0xca, 0x39, 0xf0, 0xb1, 0x7a, 0xd6, 0x69, 0x5f, 0x5, 0xa1, 0xa4, 0xa3, 0x3a, 0xdf, 0x8, 0xd8, 0xcf, 0x62, 0xf7, 0x14, 0x4f, 0x5a, 0x87, 0xa5, 0xc1, 0x22, 0x51, 0xe2, 0xd5, 0x9a, 0xc1, 0x1c, 0x37, 0x5e, 0xd6, 0x7f, 0xed, 0xfb, 0x41, 0x5e, 0xb7, 0xf, 0x7c, 0xe3, 0xba, 0x7b, 0xd0, 0xa5, 0x3a, 0xb3, 0x8c, 0xd7, 0x2e, 0x4e, 0xd7, 0xba, 0xbb, 0xd7, 0xc6, 0xb, 0x8d, 0x17, 0x1f, 0xe3, 0x46, 0x9, 0x49, 0xa1, 0x8c, 0x13, 0x63, 0x4c, 0xa6, 0xfa, 0x2a, 0x8c, 0x38, 0x88, 0x6a, 0xc9, 0x32, 0x4c, 0x1b, 0xa3, 0x44, 0x43, 0xd9, 0x55, 0xdb, 0xce, 0xc1, 0xe9, 0x92, 0x2f, 0x4a, 0x25, 0x59, 0x36, 0x52, 0x52, 0x41, 0xc4, 0x16, 0x2, 0x41, 0x32, 0x7a, 0x73, 0x4b, 0x21, 0xb, 0x8, 0x57, 0x89, 0xc2, 0x90, 0x65, 0xa8, 0xdc, 0x46, 0x56, 0x14, 0x15, 0x8e, 0xc1, 0x20, 0xd7, 0xcc, 0x40, 0x76, 0x42, 0x3a, 0x83, 0xf, 0x83, 0x46, 0xf5, 0x27, 0xa7, 0x80, 0x7e, 0xcf, 0xd2, 0x74, 0xd0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char base_green_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x1, 0x3, 0x0, 0x0, 0x0, 0x49, 0xb4, 0xe8, 0xb7, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x90, 0xc9, 0xab, 0xff, 0xff, 0xff, 0xc6, 0xd0, 0x9d, 0x30, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x18, 0xdc, 0x0, 0x0, 0x0, 0xa0, 0x0, 0x1, 0x61, 0x25, 0x7d, 0x47, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x1, 0x3, 0x0, 0x0, 0x0, 0x49, 0xb4, 0xe8, 0xb7, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x90, 0xc9, 0xab, 0xff, 0xff, 0xff, 0xc6, 0xd0, 0x9d, 0x30, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0xe4, 0x0, 0x0, 0x0, 0xa0, 0x0, 0x1, 0xf3, 0xdb, 0xea, 0x79, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xd9, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x7d, 0x91, 0x41, 0x4e, 0xc3, 0x30, 0x14, 0x44, 0x9f, 0xed, 0x8f, 0x6d, 0x35, 0x8b, 0x9a, 0x6d, 0xb9, 0x6, 0xfb, 0xde, 0x81, 0xd3, 0xe4, 0x8, 0xf4, 0x32, 0xbd, 0x1, 0xb, 0x6e, 0xc0, 0x25, 0x60, 0x83, 0xa8, 0x2, 0x6a, 0xa4, 0xc6, 0x49, 0xfc, 0xbb, 0x88, 0x54, 0x11, 0x94, 0x30, 0xb3, 0xf9, 0xd2, 0x9f, 0x19, 0x8d, 0x34, 0x6, 0xc1, 0x13, 0x88, 0x78, 0x1c, 0x96, 0x9, 0x85, 0x91, 0xcc, 0x85, 0x8e, 0x2c, 0x78, 0x2a, 0x12, 0x5b, 0x2a, 0x2, 0x6, 0x3, 0x28, 0x4a, 0x47, 0xcb, 0x37, 0xd, 0x8, 0x81, 0xb4, 0x7f, 0x7a, 0xa8, 0x87, 0xc4, 0xc, 0xd2, 0xbc, 0x3f, 0xbf, 0x1e, 0x19, 0x84, 0xc8, 0x76, 0x57, 0x9f, 0xd2, 0x80, 0xfe, 0x7a, 0x1b, 0x24, 0xed, 0x6a, 0x5e, 0x38, 0xb, 0x9e, 0xaa, 0x4f, 0xfd, 0xdc, 0x8e, 0xd2, 0xd3, 0x27, 0x2a, 0xbc, 0xe0, 0x8, 0x65, 0xe6, 0xe6, 0xd6, 0x94, 0x80, 0x13, 0x2c, 0x46, 0x29, 0xb, 0x2, 0x5, 0x83, 0x15, 0xc0, 0xac, 0x26, 0x18, 0x90, 0xe9, 0x5c, 0x11, 0x30, 0x9, 0x54, 0x17, 0x5, 0xa, 0xa, 0x42, 0x41, 0xcb, 0x62, 0x87, 0x2, 0x4a, 0x11, 0x46, 0xba, 0xd5, 0x84, 0x8e, 0xd1, 0x92, 0x69, 0x6d, 0xe3, 0xd0, 0x3f, 0x74, 0xd8, 0x86, 0x96, 0xec, 0xb8, 0xc3, 0xa5, 0xaf, 0xfb, 0x47, 0x1f, 0x3d, 0xe1, 0xc6, 0x48, 0x3c, 0x7d, 0x1e, 0x3e, 0xde, 0xf8, 0x31, 0x6c, 0xfe, 0x1d, 0xab, 0x15, 0x32, 0x30, 0x70, 0x5e, 0x9b, 0xfb, 0xa, 0xbb, 0x7c, 0x61, 0xa2, 0x50, 0x44, 0x45, 0xca, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xc7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd0, 0x81, 0x66, 0x43, 0x31, 0x14, 0x87, 0xf1, 0xf, 0x5, 0x17, 0xb8, 0x28, 0x2e, 0x8, 0x71, 0xf3, 0x6, 0x19, 0xb6, 0xb9, 0xcb, 0xac, 0x95, 0xa4, 0xb7, 0xad, 0x6a, 0xd5, 0x68, 0x5f, 0xe4, 0x3e, 0x76, 0x1e, 0xe1, 0xbf, 0x21, 0xa6, 0xab, 0xf8, 0x1, 0x7c, 0x9c, 0x73, 0xe, 0xac, 0xe8, 0xe8, 0x19, 0x30, 0x58, 0xc6, 0xca, 0x62, 0x18, 0xe8, 0xe9, 0x58, 0x41, 0xc7, 0x1a, 0x87, 0x27, 0x10, 0x49, 0xe4, 0x5f, 0x89, 0x48, 0xc0, 0xe3, 0x58, 0xd3, 0x41, 0x8f, 0xb, 0xcb, 0xbd, 0x7c, 0xeb, 0xbf, 0x7b, 0x9, 0xb, 0x8e, 0x1e, 0x6, 0xfc, 0xad, 0x64, 0x6d, 0xb5, 0x79, 0xb0, 0x55, 0xd6, 0xad, 0xe0, 0x19, 0xc0, 0x10, 0xae, 0xda, 0x34, 0x5c, 0x45, 0xc0, 0x80, 0x25, 0x5e, 0xf4, 0xd5, 0x70, 0x11, 0x11, 0xb, 0x23, 0xe9, 0xac, 0xcf, 0x86, 0xb3, 0x48, 0x8c, 0x30, 0x92, 0x4f, 0xa, 0xd, 0x27, 0x91, 0x6b, 0x70, 0xd4, 0x47, 0xc3, 0xf1, 0x2f, 0x48, 0x7, 0x4d, 0xd, 0x87, 0x3a, 0xc2, 0x12, 0x67, 0xbd, 0x37, 0xcc, 0x75, 0x49, 0x43, 0xd8, 0xe9, 0xad, 0x61, 0x57, 0xcf, 0x1c, 0xf0, 0xfb, 0x32, 0xe9, 0xf5, 0xc9, 0xa4, 0x7d, 0x7d, 0x54, 0x8f, 0x7b, 0x59, 0xe6, 0x92, 0x14, 0x1f, 0x24, 0xcd, 0x3f, 0x7b, 0x6b, 0xa, 0xe, 0x6a, 0x82, 0x91, 0x45, 0x30, 0xba, 0x1, 0x4a, 0x51, 0xc4, 0x35, 0x1f, 0xe5, 0xa1, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x4, 0x42, 0x26, 0xa1, 0xa1, 0xce, 0x8a, 0x40, 0x46, 0x7a, 0xe7, 0xcc, 0x99, 0x33, 0xca, 0x80, 0x8c, 0xd5, 0x20, 0xe1, 0x5d, 0x40, 0x1c, 0x3, 0x62, 0x1c, 0x5, 0xe2, 0x48, 0x10, 0x63, 0x2a, 0x7e, 0x6, 0x5c, 0x31, 0x58, 0xbb, 0x14, 0x10, 0xe7, 0xee, 0x9c, 0x39, 0x73, 0x1e, 0xc8, 0x40, 0x31, 0x98, 0x15, 0xe8, 0x0, 0x0, 0xec, 0xe0, 0x11, 0x6d, 0x2c, 0x6f, 0x45, 0x2b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x62, 0xed, 0x5e, 0xfc, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0x84, 0x4c, 0x42, 0x43, 0x9d, 0x15, 0x81, 0x8c, 0xf4, 0xce, 0x99, 0x33, 0x67, 0x94, 0x1, 0x19, 0xab, 0x41, 0xc2, 0xbb, 0x80, 0x38, 0x6, 0xc4, 0x38, 0xa, 0xc4, 0x91, 0x20, 0xc6, 0x54, 0x3c, 0xc, 0xb8, 0x62, 0x98, 0x76, 0x29, 0x20, 0xce, 0xdd, 0x39, 0x73, 0xe6, 0x3c, 0x90, 0x81, 0x62, 0x10, 0x2b, 0x30, 0x1, 0x0, 0xec, 0xe0, 0x11, 0x6d, 0xb5, 0xe0, 0x8c, 0x99, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_hover_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x5f, 0x5a, 0x6b, 0x56, 0x53, 0x64, 0x57, 0x53, 0x64, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x57, 0x53, 0x63, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5b, 0x57, 0x66, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x43, 0x40, 0x4c, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0xff, 0xff, 0xff, 0x99, 0x8b, 0x2e, 0x55, 0x0, 0x0, 0x0, 0x16, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0x6b, 0x28, 0x52, 0x7a, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x2e, 0x54, 0xd3, 0x10, 0x87, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x97, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x49, 0x12, 0x82, 0x30, 0x10, 0x5, 0xd0, 0xce, 0x48, 0x46, 0x40, 0x51, 0x4, 0x41, 0x45, 0xc4, 0x20, 0x88, 0xf7, 0xbf, 0x9e, 0x21, 0x45, 0x65, 0xa1, 0x6f, 0xd7, 0xbf, 0xaa, 0x27, 0x0, 0x84, 0x9, 0x65, 0xdc, 0x63, 0x94, 0x60, 0x4, 0x80, 0x12, 0x21, 0x95, 0x36, 0xd6, 0x1a, 0xad, 0xa4, 0x48, 0x10, 0x60, 0x91, 0x66, 0xe5, 0x29, 0x28, 0xb3, 0x54, 0x60, 0x20, 0x32, 0xaf, 0xea, 0x73, 0x50, 0x57, 0xb9, 0x24, 0x40, 0x55, 0xb3, 0xd5, 0x3e, 0x69, 0x14, 0x5, 0xa6, 0xdb, 0x4b, 0xd4, 0x6a, 0x6, 0xdc, 0x5c, 0x6f, 0xd1, 0xd5, 0x70, 0xe0, 0xb6, 0xbb, 0x47, 0x9d, 0x5d, 0x83, 0xfe, 0x11, 0xf5, 0x6b, 0x60, 0x86, 0x67, 0x34, 0xf8, 0x16, 0xa6, 0xdd, 0x18, 0x39, 0x3f, 0x94, 0x2a, 0x37, 0xbe, 0x36, 0xa3, 0xf3, 0x6b, 0x89, 0xdc, 0x4d, 0xf3, 0x3b, 0x98, 0xa7, 0xbd, 0x3f, 0xc, 0x8b, 0xe2, 0xb0, 0x7c, 0x82, 0xe5, 0x58, 0xf8, 0xd3, 0xff, 0x9e, 0xfb, 0x7d, 0xff, 0xb, 0x74, 0xeb, 0x15, 0x11, 0xe1, 0xa7, 0x60, 0xfc, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x5f, 0x5a, 0x6b, 0x56, 0x53, 0x64, 0x57, 0x53, 0x64, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x57, 0x53, 0x63, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5b, 0x57, 0x66, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x43, 0x40, 0x4c, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x40, 0xdc, 0xe6, 0x80, 0x0, 0x0, 0x0, 0x16, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0x6b, 0x28, 0x52, 0x7a, 0x0, 0x0, 0x0, 0x67, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xcf, 0x47, 0x2, 0x83, 0x30, 0x10, 0x43, 0x51, 0x69, 0x98, 0xf4, 0xe4, 0xfe, 0x87, 0x24, 0xfb, 0xf4, 0x8, 0xd1, 0xb1, 0x3f, 0xb8, 0xbd, 0xdd, 0x24, 0x38, 0x4, 0x40, 0x43, 0xc9, 0xfd, 0x24, 0x1a, 0x7a, 0x27, 0x2d, 0x7, 0xc2, 0x41, 0x2f, 0xbd, 0x69, 0x88, 0x23, 0x27, 0x38, 0x3d, 0xfd, 0x22, 0x2f, 0xd3, 0x1b, 0xc3, 0x35, 0xe9, 0x85, 0x39, 0xd, 0x10, 0x2c, 0x0, 0x25, 0x20, 0x81, 0x2d, 0xc0, 0xa0, 0x2d, 0x8, 0xa9, 0x12, 0x64, 0x0, 0x66, 0x91, 0xa5, 0x61, 0xf3, 0xbe, 0xc5, 0x18, 0xd9, 0x7e, 0x7e, 0x21, 0x45, 0x1b, 0x53, 0x77, 0x4a, 0xac, 0x87, 0x63, 0x3d, 0x7e, 0x7, 0x87, 0x7b, 0x3b, 0x5b, 0x7a, 0xd3, 0xea, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_normal_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0xff, 0xff, 0xff, 0xe5, 0x37, 0x10, 0x78, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x2d, 0xcd, 0xda, 0x41, 0x3d, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x93, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x47, 0x12, 0x82, 0x40, 0x10, 0x5, 0xd0, 0x9e, 0xc8, 0x44, 0x92, 0x22, 0x41, 0x54, 0x44, 0x40, 0x14, 0xef, 0x7f, 0x3e, 0x7, 0x8a, 0xea, 0x85, 0xbe, 0xe5, 0xaf, 0xea, 0xf0, 0x1, 0x8, 0x65, 0x5c, 0xc8, 0x40, 0x70, 0x46, 0x9, 0x0, 0x89, 0x94, 0x36, 0xd6, 0x79, 0xef, 0xac, 0xd1, 0x2a, 0x22, 0x40, 0x55, 0x9c, 0x14, 0xa7, 0x4d, 0x91, 0xc4, 0x8a, 0x2, 0xd3, 0x69, 0x59, 0xd5, 0x9b, 0xaa, 0x4c, 0x35, 0x3, 0x6e, 0x9a, 0xfa, 0xbc, 0xab, 0x1b, 0xc3, 0x41, 0xd8, 0xf6, 0x82, 0x5a, 0x2b, 0x40, 0xba, 0xeb, 0xd, 0x5d, 0x9d, 0x4, 0xe9, 0xbb, 0x3b, 0xea, 0xfc, 0x1a, 0xf4, 0xf, 0xd4, 0xaf, 0x81, 0x1b, 0x46, 0x34, 0x84, 0x11, 0x61, 0xa7, 0x27, 0x9a, 0xc2, 0x52, 0x6e, 0xe6, 0x17, 0x9a, 0xc3, 0x59, 0xa6, 0xb3, 0xf1, 0xbd, 0x1b, 0xb3, 0xf0, 0x18, 0x55, 0xf9, 0x61, 0xf9, 0x6c, 0x96, 0x63, 0x1e, 0x5e, 0xff, 0x2b, 0xf7, 0x5b, 0xff, 0xb, 0x69, 0x5a, 0x14, 0xfa, 0x84, 0xf6, 0xc2, 0x8, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x14, 0x4, 0xd1, 0x2e, 0x1c, 0xee, 0x7f, 0xca, 0xd1, 0xed, 0x28, 0x8d, 0x4b, 0x92, 0x5a, 0xbe, 0xe8, 0x2f, 0xc4, 0x9c, 0x24, 0xcf, 0x15, 0x54, 0xab, 0x78, 0xee, 0x53, 0x30, 0x4a, 0x85, 0xa6, 0xfc, 0xf1, 0x87, 0x11, 0xb2, 0x9a, 0x15, 0x9a, 0x37, 0x13, 0x74, 0xce, 0xb4, 0xd4, 0x77, 0xcb, 0xe, 0xb4, 0x96, 0x99, 0x10, 0x34, 0x81, 0x42, 0x50, 0x21, 0x9d, 0x41, 0x23, 0xf8, 0xc, 0x56, 0xe1, 0x10, 0x9c, 0x40, 0x4e, 0xfe, 0x6e, 0x72, 0x96, 0x7e, 0xd7, 0xdf, 0x3f, 0xb3, 0x79, 0x90, 0xcd, 0xf1, 0xc4, 0x26, 0x1e, 0x8e, 0x78, 0xfc, 0x1, 0xf5, 0x61, 0x3f, 0x44, 0xe8, 0xf1, 0xdd, 0xba, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_pressed_png[] = {
@@ -39,19 +39,19 @@ static const unsigned char button_pressed_png[] = {
};
static const unsigned char checked_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x12, 0x7b, 0xbc, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x8e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x5b, 0x12, 0x82, 0x30, 0xc, 0x40, 0x51, 0x48, 0x5b, 0x15, 0x5, 0x5b, 0x42, 0x2b, 0x4, 0x50, 0x40, 0xc5, 0xb7, 0xee, 0x7f, 0x79, 0x96, 0x8a, 0x88, 0x7a, 0x3f, 0xcf, 0x4c, 0x26, 0x89, 0xe7, 0xfd, 0xe5, 0x3, 0xe3, 0xc2, 0x35, 0x99, 0x82, 0x6f, 0x1, 0x66, 0x81, 0x54, 0xae, 0x18, 0xe7, 0x60, 0x81, 0x5, 0x89, 0x36, 0x5d, 0xab, 0x34, 0x5b, 0x30, 0xb, 0x5c, 0x6a, 0xa2, 0xbc, 0x20, 0x2a, 0x71, 0x2d, 0xb9, 0x5, 0xa1, 0xc, 0x6d, 0xb0, 0xa2, 0x1a, 0x9b, 0xad, 0x12, 0x3d, 0xec, 0x70, 0xdf, 0x36, 0x58, 0x9b, 0x1, 0xe, 0xc7, 0xd3, 0x19, 0x4b, 0xfa, 0x80, 0x9d, 0xc9, 0xd2, 0xcb, 0x18, 0xae, 0x88, 0x37, 0x1a, 0x43, 0x91, 0xdf, 0x1f, 0x6f, 0x70, 0x6b, 0x5f, 0x69, 0xb7, 0x76, 0x38, 0xcc, 0xe8, 0x24, 0xec, 0xe, 0x83, 0x28, 0xec, 0x4f, 0x97, 0xcb, 0x8, 0xbe, 0x9e, 0xe3, 0xcc, 0x3d, 0xf7, 0xd3, 0x13, 0x10, 0x58, 0xd, 0x44, 0xd4, 0xa5, 0x38, 0x3e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xca, 0x5, 0xb2, 0x2, 0x30, 0x18, 0x3, 0xe1, 0x4d, 0xed, 0xb9, 0x60, 0xf7, 0x3f, 0x20, 0xee, 0x4e, 0x99, 0xe0, 0xb0, 0x63, 0xfd, 0xbf, 0x86, 0xd7, 0x12, 0x72, 0x38, 0x69, 0x5b, 0x6b, 0x42, 0x45, 0xe5, 0xa, 0xab, 0x95, 0x41, 0x9f, 0x32, 0x20, 0x69, 0x2d, 0xbc, 0x50, 0x46, 0x3a, 0x10, 0x17, 0x5f, 0x49, 0x4, 0x7f, 0x90, 0x57, 0x89, 0xb7, 0xc5, 0x5f, 0x96, 0x17, 0x2e, 0x93, 0xcb, 0x8e, 0x3a, 0x83, 0xb, 0xc4, 0x8e, 0xd4, 0xff, 0x5c, 0x73, 0x83, 0x69, 0x9e, 0x95, 0xfc, 0x3b, 0xf4, 0x33, 0xe0, 0xf8, 0x61, 0xd3, 0xf1, 0x7d, 0x5d, 0x30, 0x7a, 0x6f, 0x89, 0xb, 0xd4, 0x5a, 0xe1, 0x40, 0xf, 0xfc, 0x34, 0x6c, 0xd2, 0x56, 0x80, 0xef, 0xfd, 0x9, 0xd2, 0x3a, 0x5e, 0x41, 0x15, 0x21, 0x77, 0x6, 0xc7, 0x6b, 0x47, 0x4e, 0x3a, 0x2f, 0x53, 0xb4, 0x10, 0xc7, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char checker_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1a, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc4, 0x0, 0x5, 0x98, 0xc, 0xc6, 0x7a, 0xc2, 0x6a, 0x0, 0x8b, 0x7a, 0x2, 0x8d, 0x68, 0x67, 0xe3, 0xa, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char close_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x67, 0xdb, 0x58, 0xd0, 0xd3, 0xf0, 0xa3, 0x7c, 0x36, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x85, 0x14, 0x81, 0xf, 0x2c, 0x28, 0xe0, 0xda, 0xd5, 0x8c, 0x4e, 0x77, 0xb, 0xfc, 0xd5, 0x98, 0xd9, 0x20, 0x29, 0x7a, 0xb9, 0xa4, 0x68, 0x66, 0x83, 0xb, 0x93, 0xcc, 0x24, 0xa7, 0x9a, 0x44, 0x52, 0x24, 0x39, 0x91, 0xcc, 0x55, 0x89, 0xa4, 0xde, 0xcc, 0xce, 0x24, 0xb, 0xc9, 0x39, 0x84, 0xb0, 0xf7, 0xb2, 0xae, 0xeb, 0x76, 0xde, 0x8a, 0x4f, 0x92, 0x66, 0xd8, 0x91, 0x5c, 0x49, 0x5e, 0x9a, 0xe1, 0xb5, 0x64, 0x5, 0x16, 0x92, 0x8b, 0x7, 0x6f, 0x9b, 0x8c, 0x0, 0x4a, 0x29, 0x9b, 0x26, 0x81, 0xa4, 0x3e, 0xa5, 0x34, 0x2, 0x38, 0x2, 0x58, 0x0, 0xcc, 0x0, 0xe, 0x39, 0xe7, 0xd3, 0xfa, 0xb0, 0xee, 0xea, 0x8f, 0x7, 0x7b, 0xf5, 0x9d, 0xb7, 0xb0, 0x97, 0x55, 0x25, 0x5f, 0x17, 0xe9, 0x2e, 0xf9, 0xb8, 0xca, 0x3f, 0x9b, 0x1b, 0x1a, 0xe3, 0x40, 0x47, 0xa0, 0xda, 0xda, 0x61, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char close_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x67, 0xdb, 0x58, 0xd0, 0xd3, 0xf0, 0xa3, 0x7c, 0x36, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x85, 0x14, 0x81, 0xf, 0x2c, 0x28, 0xe0, 0xda, 0xd5, 0x8c, 0x4e, 0x77, 0xb, 0xfc, 0xd5, 0x98, 0xd9, 0x20, 0x29, 0x7a, 0xb9, 0xa4, 0x68, 0x66, 0x83, 0xb, 0x93, 0xcc, 0x24, 0xa7, 0x9a, 0x44, 0x52, 0x24, 0x39, 0x91, 0xcc, 0x55, 0x89, 0xa4, 0xde, 0xcc, 0xce, 0x24, 0xb, 0xc9, 0x39, 0x84, 0xb0, 0xf7, 0xb2, 0xae, 0xeb, 0x76, 0xde, 0x8a, 0x4f, 0x92, 0x66, 0xd8, 0x91, 0x5c, 0x49, 0x5e, 0x9a, 0xe1, 0xb5, 0x64, 0x5, 0x16, 0x92, 0x8b, 0x7, 0x6f, 0x9b, 0x8c, 0x0, 0x4a, 0x29, 0x9b, 0x26, 0x81, 0xa4, 0x3e, 0xa5, 0x34, 0x2, 0x38, 0x2, 0x58, 0x0, 0xcc, 0x0, 0xe, 0x39, 0xe7, 0xd3, 0xfa, 0xb0, 0xee, 0xea, 0x8f, 0x7, 0x7b, 0xf5, 0x9d, 0xb7, 0xb0, 0x97, 0x55, 0x25, 0x5f, 0x17, 0xe9, 0x2e, 0xf9, 0xb8, 0xca, 0x3f, 0x9b, 0x1b, 0x1a, 0xe3, 0x40, 0x47, 0xa0, 0xda, 0xda, 0x61, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char color_picker_hue_png[] = {
@@ -59,31 +59,31 @@ static const unsigned char color_picker_hue_png[] = {
};
static const unsigned char color_picker_sample_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x2, 0x0, 0x0, 0x0, 0xed, 0x20, 0x74, 0x8, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x9, 0x18, 0xc, 0x27, 0x37, 0x29, 0x4f, 0x42, 0x2d, 0x0, 0x0, 0x0, 0x61, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9, 0xb1, 0xd, 0x0, 0x21, 0xc, 0x3, 0x40, 0x40, 0xbf, 0x5f, 0x66, 0xcd, 0x84, 0xf9, 0x96, 0x19, 0xf0, 0x5d, 0x87, 0x5c, 0x5b, 0x9, 0xca, 0x9e, 0x99, 0x75, 0xe9, 0xee, 0xfb, 0x59, 0x55, 0x52, 0xe9, 0xc3, 0xe9, 0x59, 0x10, 0x4c, 0x1, 0x50, 0x0, 0x50, 0x0, 0x8, 0xf4, 0xf9, 0x15, 0x49, 0x93, 0x53, 0x13, 0x0, 0x2b, 0x10, 0x28, 0x0, 0x28, 0x0, 0x64, 0xd9, 0x2e, 0xc1, 0xd2, 0xe4, 0xd4, 0x4, 0xc0, 0xa, 0x4, 0xa, 0x0, 0xa, 0x0, 0x59, 0x5c, 0x82, 0xa5, 0xd1, 0xa9, 0x9, 0x80, 0x15, 0x8, 0x14, 0x0, 0x14, 0x0, 0xb2, 0xfc, 0x5b, 0xb2, 0x3c, 0x5a, 0x4, 0xa1, 0xf3, 0x57, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x47, 0x29, 0xbc, 0x83, 0x0, 0x0, 0x0, 0x3c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xd5, 0x21, 0x11, 0x0, 0x30, 0xc, 0x4, 0xc1, 0xfa, 0x57, 0x53, 0x87, 0xed, 0x4, 0x45, 0xc4, 0xed, 0xa3, 0xc3, 0x4b, 0xfe, 0xbc, 0xd9, 0x9d, 0x35, 0x2b, 0xe, 0x0, 0x0, 0x0, 0x80, 0xed, 0x66, 0xc5, 0x1, 0x0, 0x0, 0x0, 0xe0, 0x6, 0x1, 0x0, 0x0, 0x90, 0x6, 0x70, 0x83, 0x0, 0x0, 0x0, 0x28, 0x3, 0x7c, 0x54, 0x93, 0xd6, 0xf1, 0xd1, 0x16, 0x8a, 0x17, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char dosfont_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x0, 0xeb, 0x45, 0x5c, 0x66, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x1, 0xdd, 0x8a, 0x13, 0xa4, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x89, 0x0, 0x0, 0xb, 0x89, 0x1, 0x37, 0xc9, 0xcb, 0xad, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x2, 0x83, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0xd4, 0xb1, 0x6e, 0xdb, 0x30, 0x10, 0x0, 0x50, 0x22, 0x3, 0x27, 0x22, 0xc8, 0x78, 0x83, 0x91, 0xa9, 0x1f, 0xc0, 0xa9, 0x10, 0xa, 0x7e, 0xc, 0x11, 0x14, 0x87, 0xc, 0x1c, 0x32, 0x9, 0x1a, 0xe, 0x46, 0xa6, 0xfc, 0x43, 0xff, 0x86, 0xb5, 0x80, 0x9b, 0x88, 0x8e, 0x5d, 0x64, 0x18, 0x9e, 0xdc, 0xd5, 0x53, 0x91, 0xc1, 0xa0, 0x7a, 0xa4, 0xe4, 0xd4, 0x31, 0xd2, 0x25, 0x70, 0x97, 0xa2, 0x37, 0x48, 0xe6, 0x33, 0x45, 0xdd, 0x51, 0x24, 0x95, 0x7a, 0x23, 0xe0, 0x75, 0x13, 0xb, 0xd8, 0x93, 0xbf, 0x51, 0x51, 0xa3, 0xac, 0x99, 0xc9, 0x29, 0x87, 0x81, 0x83, 0xb2, 0x0, 0xc7, 0xfe, 0xee, 0x43, 0x58, 0x85, 0x95, 0xb7, 0xa6, 0xb6, 0xaf, 0x7a, 0xe9, 0x93, 0x63, 0xc3, 0xf2, 0xc, 0x96, 0x3e, 0xba, 0x97, 0x11, 0x3, 0xb5, 0x46, 0xc0, 0x15, 0x30, 0x43, 0x1, 0xbd, 0x6, 0x81, 0x71, 0xa9, 0xb2, 0x82, 0x9, 0x92, 0x3d, 0xf6, 0xb0, 0xbd, 0x5c, 0xf2, 0x53, 0xf2, 0x75, 0xc, 0x11, 0x5f, 0xc7, 0xe0, 0xc4, 0xaa, 0xb4, 0x40, 0x41, 0xc4, 0x69, 0xd0, 0x27, 0x55, 0x12, 0x13, 0x78, 0x74, 0xa7, 0xb5, 0xd8, 0x3f, 0x14, 0x77, 0x81, 0x0, 0x22, 0x93, 0x9b, 0x4c, 0x54, 0x5b, 0x72, 0x6d, 0x98, 0x17, 0xd1, 0x33, 0xb3, 0x94, 0xaa, 0x3c, 0x93, 0xea, 0xb4, 0x76, 0x31, 0x6a, 0x66, 0x0, 0xa9, 0x59, 0x1c, 0x8c, 0xe, 0x33, 0xc0, 0x12, 0x4c, 0x29, 0xc2, 0xa5, 0xc3, 0xc1, 0xd0, 0xb2, 0x64, 0x6a, 0x60, 0xa3, 0xc0, 0xea, 0xac, 0x19, 0x58, 0x4b, 0xa9, 0x4a, 0x17, 0xf0, 0xda, 0x68, 0xb6, 0x5, 0xec, 0xb2, 0xf6, 0x88, 0x33, 0xc8, 0x18, 0x52, 0xd5, 0x5a, 0x1, 0xb3, 0x61, 0x1, 0x53, 0xdf, 0x2, 0x51, 0x2d, 0x33, 0xdd, 0x12, 0x59, 0xea, 0x94, 0x95, 0x3c, 0x80, 0x2e, 0x5e, 0xf9, 0xdb, 0x71, 0x73, 0x70, 0xcf, 0x39, 0x3b, 0x76, 0xb7, 0xbb, 0x7d, 0xcf, 0x74, 0x50, 0xd, 0x62, 0x40, 0x44, 0x6, 0x83, 0xfe, 0xc7, 0x8e, 0x51, 0x5, 0x5c, 0xe1, 0xdd, 0xdd, 0xaa, 0xc2, 0xf8, 0x53, 0x80, 0x31, 0xe2, 0xfd, 0x7d, 0x14, 0x8, 0x7e, 0xcc, 0x5, 0x28, 0x62, 0xd7, 0xc5, 0xc, 0xa6, 0xf3, 0xc3, 0x46, 0xa6, 0x30, 0xd7, 0x1e, 0x1b, 0x2e, 0xd0, 0x7f, 0x63, 0x5f, 0x1f, 0xf1, 0x32, 0xc9, 0x90, 0x82, 0xef, 0xb9, 0x82, 0xc, 0x5a, 0x1, 0xef, 0x66, 0x90, 0xd7, 0x7a, 0x2c, 0x80, 0x13, 0x94, 0xc4, 0xf6, 0x9f, 0xd8, 0x75, 0xbb, 0x2c, 0x89, 0xed, 0xff, 0x42, 0xe9, 0xa7, 0xfb, 0xa4, 0x84, 0xec, 0x13, 0x45, 0x7, 0x1a, 0xb9, 0x97, 0x18, 0x65, 0xab, 0x4, 0xf9, 0x54, 0x8c, 0x3c, 0x54, 0xe8, 0xed, 0xa3, 0x7c, 0x7b, 0x55, 0xe0, 0x8b, 0x0, 0xf6, 0x4f, 0x36, 0xd6, 0x3d, 0xc3, 0xe8, 0x41, 0xc0, 0xa1, 0xb1, 0xdb, 0x9, 0xa8, 0x29, 0x0, 0xe, 0xec, 0xc3, 0x4, 0xc1, 0x8, 0xc, 0x0, 0xd6, 0x36, 0xf3, 0x23, 0xba, 0x80, 0x3, 0x6f, 0x17, 0x15, 0xbe, 0x4b, 0xe5, 0x8c, 0x23, 0xc2, 0x57, 0x7b, 0x5d, 0x61, 0x53, 0xc0, 0x61, 0xf, 0xbd, 0xd5, 0x15, 0x68, 0x47, 0x8e, 0x0, 0x7b, 0x37, 0xba, 0xab, 0xba, 0x59, 0xcc, 0x79, 0x3d, 0xd7, 0xaf, 0x5a, 0xe3, 0x85, 0x66, 0x69, 0xab, 0x16, 0x32, 0x31, 0x5b, 0xd0, 0xdb, 0x66, 0x2, 0x2f, 0x6f, 0xe, 0xb2, 0x42, 0xb5, 0x87, 0xdf, 0xf0, 0x59, 0xae, 0x6a, 0x86, 0xae, 0x93, 0x4c, 0x7d, 0x1b, 0x9a, 0x6b, 0x84, 0xdd, 0x9a, 0xd6, 0xca, 0xc8, 0x89, 0xc3, 0xfb, 0xd4, 0x82, 0xe, 0x30, 0xa2, 0x2c, 0x18, 0xc2, 0x98, 0xb2, 0x4f, 0x8, 0xba, 0x83, 0xa1, 0x40, 0x12, 0x88, 0x6f, 0x43, 0x38, 0x82, 0x1c, 0x1f, 0x15, 0x70, 0x82, 0x96, 0xa8, 0xa5, 0x3d, 0xed, 0x9c, 0xde, 0xb9, 0x1, 0xe9, 0xb8, 0x5f, 0x4c, 0x39, 0xd2, 0xa6, 0xac, 0xa6, 0x48, 0xe7, 0xd0, 0x95, 0x53, 0xb0, 0xc4, 0x7b, 0x97, 0xd4, 0xcd, 0x3c, 0xdd, 0xf0, 0xd0, 0x4e, 0xbf, 0xe6, 0x65, 0x24, 0x5b, 0x7b, 0x7d, 0xe, 0xe5, 0xd6, 0xae, 0xe9, 0x90, 0x64, 0xfd, 0x70, 0x9e, 0x21, 0xb5, 0x6c, 0x5, 0xa4, 0xa2, 0x87, 0xe9, 0xa3, 0x25, 0xf4, 0x5, 0x5c, 0x39, 0x61, 0xa6, 0x1e, 0xbe, 0x11, 0x18, 0x80, 0xed, 0xb, 0x18, 0x9b, 0x70, 0x70, 0xec, 0x5f, 0x80, 0x3f, 0x26, 0x27, 0xb3, 0xc9, 0x33, 0xc8, 0x5c, 0x2c, 0x5a, 0x59, 0x1f, 0xcb, 0x2c, 0x89, 0x9d, 0xae, 0xf, 0x7d, 0xcc, 0xdb, 0x9c, 0xdd, 0xd5, 0xed, 0x7c, 0x7f, 0xbe, 0xd0, 0x52, 0xf9, 0x1f, 0xff, 0x76, 0xfc, 0x2, 0x24, 0x3a, 0x65, 0x42, 0xf6, 0x41, 0x91, 0x95, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x0, 0xeb, 0x45, 0x5c, 0x66, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x2, 0x64, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xbc, 0xd4, 0x81, 0x86, 0x2c, 0x47, 0x14, 0xc6, 0xf1, 0xcf, 0x45, 0x81, 0x32, 0x2, 0x38, 0x58, 0x17, 0xe4, 0x1, 0xa, 0x44, 0x8b, 0x7a, 0x98, 0xb2, 0xe2, 0xb8, 0x28, 0x2c, 0x68, 0x8d, 0x63, 0x5c, 0xb0, 0xef, 0x90, 0xb7, 0xe9, 0x6c, 0x71, 0x40, 0x9, 0x20, 0xd0, 0x63, 0x2d, 0x98, 0x0, 0xc, 0x88, 0x60, 0x54, 0xa7, 0xaa, 0xba, 0xef, 0x66, 0x67, 0x5d, 0x10, 0x37, 0xf7, 0xf, 0xc3, 0x4f, 0x39, 0x53, 0x87, 0xd2, 0xf8, 0x5a, 0x84, 0x9b, 0xb8, 0x81, 0xc3, 0x6b, 0xc4, 0x90, 0x1, 0xce, 0xee, 0xe4, 0xe1, 0x39, 0x6a, 0x84, 0x23, 0xda, 0x80, 0xe1, 0x7f, 0x8c, 0x4f, 0xf1, 0x29, 0x38, 0x8b, 0xd6, 0x87, 0x4, 0x8f, 0x32, 0xf, 0xa, 0x67, 0x99, 0x2a, 0x98, 0x4, 0x42, 0x94, 0xd1, 0x56, 0xf0, 0xd, 0xec, 0xd2, 0xc0, 0x9c, 0xa8, 0xc2, 0x7a, 0x44, 0x1, 0x6d, 0x90, 0xdd, 0x97, 0x13, 0x2e, 0x1, 0x28, 0x8f, 0x39, 0xf4, 0x19, 0x55, 0x42, 0x9f, 0xa1, 0x59, 0x41, 0x4, 0x10, 0x68, 0xe6, 0x6d, 0xe8, 0x23, 0xac, 0xeb, 0xf0, 0xd9, 0xbf, 0xdd, 0xc5, 0xdd, 0x2c, 0xf7, 0x4d, 0x23, 0x11, 0x5b, 0x86, 0x22, 0x82, 0x96, 0x0, 0x83, 0xea, 0xdd, 0x1c, 0x54, 0x15, 0x30, 0x8, 0x2a, 0x98, 0x8c, 0xf1, 0xf3, 0x6c, 0x54, 0x89, 0x2c, 0x5c, 0x75, 0xb2, 0x26, 0xee, 0x40, 0x47, 0xb2, 0x15, 0xc8, 0xe7, 0xeb, 0xd5, 0xca, 0x11, 0x70, 0xb0, 0xf4, 0xc, 0x72, 0xa6, 0x18, 0x25, 0x35, 0x40, 0x80, 0x69, 0x10, 0x8c, 0x35, 0xea, 0x1a, 0xb8, 0xa3, 0x6d, 0x30, 0xef, 0x40, 0x44, 0x20, 0x9c, 0x40, 0xaa, 0x56, 0x2b, 0xd8, 0xfe, 0x2f, 0x34, 0xe3, 0x58, 0xe4, 0xa3, 0x88, 0x93, 0x9, 0xce, 0x20, 0x90, 0xe0, 0xfb, 0xf4, 0xc3, 0xd5, 0xff, 0x5d, 0x8a, 0x57, 0xff, 0xf1, 0x7c, 0x49, 0x2a, 0x57, 0xc, 0xcc, 0x91, 0x99, 0x95, 0x2c, 0x87, 0x3f, 0xcf, 0xca, 0x88, 0xfc, 0xc4, 0xf7, 0xf7, 0x4f, 0x1d, 0xd6, 0xbf, 0x2a, 0x28, 0xcf, 0xfc, 0xe9, 0xd3, 0x5c, 0x21, 0x86, 0xb5, 0x34, 0x90, 0x99, 0xa7, 0x69, 0x2e, 0x64, 0xa7, 0xb0, 0x3c, 0xab, 0xa0, 0xf4, 0x13, 0xcf, 0xda, 0x20, 0xfd, 0xae, 0x1, 0x5a, 0x21, 0x4, 0x55, 0xca, 0x31, 0x24, 0x6d, 0xd0, 0x86, 0x76, 0xe0, 0xfb, 0x1d, 0x38, 0x72, 0xe0, 0x6, 0xbc, 0x41, 0xbb, 0xd8, 0xe5, 0x67, 0xf5, 0xd3, 0xb9, 0x24, 0x95, 0xcb, 0xff, 0xb0, 0x3a, 0xdc, 0x2d, 0xc, 0x15, 0xe4, 0x2a, 0xab, 0xa6, 0xda, 0xea, 0xe1, 0x23, 0x8, 0xca, 0xba, 0x74, 0x48, 0xee, 0xb3, 0x55, 0xa0, 0xc1, 0xaf, 0x15, 0x38, 0x3d, 0xba, 0xd9, 0xa2, 0x43, 0xa0, 0xa, 0x9e, 0xad, 0x7b, 0xd9, 0x40, 0x86, 0x6, 0xe4, 0xc9, 0x3d, 0x6c, 0x10, 0x6d, 0x85, 0x85, 0xc8, 0xb9, 0x61, 0x3, 0x36, 0xd, 0x3c, 0x5, 0x77, 0xd7, 0xe1, 0xf, 0x56, 0x52, 0x5e, 0x99, 0x7e, 0x73, 0x87, 0xe, 0xcf, 0xd, 0x3c, 0x27, 0x4a, 0xce, 0x74, 0x90, 0xb3, 0x78, 0x21, 0x4e, 0x7e, 0xf5, 0x1f, 0x7c, 0x83, 0xaa, 0xb7, 0x1d, 0xf0, 0xb6, 0x15, 0xdf, 0xa6, 0x17, 0xdc, 0x61, 0xc0, 0xb, 0x99, 0x97, 0x61, 0x83, 0x0, 0x8b, 0x88, 0x40, 0x26, 0xd0, 0xbf, 0xf0, 0xb, 0x2, 0xb0, 0xc3, 0x34, 0x89, 0x97, 0x30, 0xc6, 0xe1, 0xc0, 0x74, 0x3e, 0xc9, 0x9, 0x36, 0x6a, 0xd4, 0x4b, 0x1e, 0xc9, 0x44, 0x5a, 0x59, 0x19, 0xc2, 0x73, 0x2e, 0x21, 0x33, 0x99, 0x89, 0x96, 0x6, 0xb9, 0xc2, 0xfc, 0x75, 0x88, 0x5f, 0x40, 0xb3, 0x76, 0xe0, 0xd, 0x46, 0x91, 0x51, 0x2e, 0x72, 0xf6, 0xe6, 0xec, 0x17, 0x16, 0xc1, 0x96, 0x5, 0x18, 0xad, 0xb0, 0x43, 0x7e, 0xf, 0x13, 0xe0, 0xd1, 0xba, 0xfc, 0xe7, 0x77, 0xd3, 0x3b, 0xd0, 0xc3, 0x78, 0xf3, 0xb9, 0x22, 0xa2, 0xd3, 0x7b, 0x40, 0x6d, 0x3c, 0xc9, 0x35, 0xa7, 0x94, 0xb4, 0xec, 0x90, 0x47, 0x75, 0x15, 0x58, 0xf3, 0x3, 0xe, 0x1d, 0x38, 0x34, 0xf0, 0x4a, 0xb5, 0xe, 0x61, 0xa8, 0xb0, 0x90, 0xba, 0x57, 0xb0, 0x2e, 0xf3, 0xe2, 0x35, 0xbc, 0x82, 0xfe, 0x94, 0xfd, 0xca, 0xaa, 0x3b, 0xc8, 0x45, 0xee, 0x46, 0xe2, 0x74, 0x2c, 0xf5, 0x62, 0x6f, 0xdf, 0x87, 0xc1, 0x9e, 0x7d, 0xf7, 0xfb, 0xcf, 0x18, 0xe4, 0xa0, 0xf4, 0xf, 0x22, 0x3c, 0x3d, 0xa, 0x46, 0x1, 0x0, 0x24, 0x3a, 0x65, 0x42, 0x42, 0xc7, 0x4f, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char dropdown_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x5, 0x1f, 0x98, 0x19, 0x18, 0x18, 0x3f, 0x30, 0xff, 0xd3, 0x83, 0x70, 0xff, 0x33, 0x33, 0x30, 0x8, 0x9f, 0x61, 0xf9, 0x6b, 0xff, 0x65, 0x2f, 0x3, 0x1c, 0xbc, 0xea, 0x66, 0x62, 0xbc, 0xcf, 0xc0, 0xc0, 0xf0, 0x7, 0x26, 0xc0, 0x74, 0x89, 0x89, 0xe9, 0x29, 0x9f, 0x14, 0x3, 0xb, 0xc3, 0x5f, 0x6, 0x6, 0x6, 0x6, 0xee, 0x38, 0x91, 0x25, 0xc, 0xc, 0xc, 0x1f, 0xd8, 0xde, 0x4b, 0x3e, 0xfc, 0xff, 0xf0, 0xff, 0x9b, 0x58, 0xb8, 0xce, 0xf, 0x6c, 0xef, 0xe4, 0xde, 0xa4, 0x32, 0x20, 0x83, 0xf, 0x4c, 0x30, 0x16, 0x0, 0x75, 0xad, 0x1b, 0x7f, 0x65, 0xec, 0x78, 0x4c, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x2, 0x60, 0x16, 0x98, 0x78, 0x67, 0x8, 0x81, 0x6f, 0x4d, 0xde, 0x9a, 0x0, 0x5, 0xde, 0x3a, 0x3d, 0xfc, 0x8f, 0x80, 0xaf, 0xba, 0x18, 0xde, 0x29, 0x2, 0x19, 0xbf, 0x61, 0x2, 0x6f, 0x62, 0x18, 0x3e, 0xb0, 0xbd, 0x97, 0x4, 0x32, 0xff, 0x80, 0xb9, 0xb1, 0x20, 0x93, 0xc0, 0x42, 0x8, 0x2e, 0x54, 0xe8, 0x9d, 0xdc, 0x9b, 0x54, 0x10, 0xb, 0x21, 0xc4, 0x4, 0x63, 0x1, 0x0, 0x86, 0x1f, 0x3b, 0x1e, 0x92, 0x22, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char error_icon_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x4, 0x0, 0x0, 0x0, 0xd9, 0x73, 0xb2, 0x7f, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x94, 0xc1, 0xe, 0x80, 0x20, 0xc, 0x43, 0x5b, 0xe3, 0xff, 0xff, 0x72, 0x3d, 0xcc, 0x85, 0xa1, 0xbb, 0x18, 0xf4, 0x62, 0xca, 0xa9, 0x74, 0xe3, 0x65, 0xd, 0x1, 0xa, 0x6b, 0x6b, 0x5b, 0x3c, 0x6f, 0x80, 0x1, 0x7f, 0x1, 0xec, 0x29, 0x78, 0xbe, 0x2a, 0x31, 0x94, 0x98, 0x9e, 0x98, 0xf5, 0xab, 0x37, 0x1, 0xaa, 0x19, 0x8d, 0xe2, 0x50, 0xb1, 0x9b, 0xbd, 0xb7, 0x23, 0x8c, 0x21, 0x7b, 0xd5, 0xf5, 0x3d, 0x88, 0x50, 0x1, 0xdf, 0x46, 0xb8, 0xf, 0x5c, 0xef, 0xa6, 0xab, 0xd1, 0x7f, 0xa2, 0x1, 0x6, 0x0, 0x0, 0xe, 0x62, 0x6, 0x31, 0x47, 0xb6, 0x7f, 0xdd, 0x14, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x4, 0x0, 0x0, 0x0, 0xd9, 0x73, 0xb2, 0x7f, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x36, 0x18, 0x5, 0xa3, 0x60, 0x14, 0xfc, 0x87, 0x40, 0x38, 0xb, 0x21, 0x6, 0x6, 0x18, 0x62, 0x98, 0x6, 0xa0, 0xb1, 0xfe, 0xe3, 0x67, 0xd1, 0xc2, 0x0, 0x10, 0xc4, 0xc5, 0x82, 0x91, 0x43, 0xc0, 0xb, 0xb8, 0x15, 0x63, 0x78, 0x6, 0x5, 0x8c, 0x82, 0x51, 0x30, 0xa, 0x0, 0x35, 0xa3, 0x4c, 0xb4, 0x7c, 0x8a, 0x7, 0x6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char frame_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xcc, 0x40, 0x27, 0xb9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x88, 0x5, 0x1d, 0x48, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xcc, 0x40, 0x27, 0xb9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char full_panel_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x44, 0xa4, 0x8a, 0xc6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0x26, 0x26, 0x28, 0x25, 0x25, 0x27, 0x24, 0x24, 0x26, 0x23, 0x23, 0x25, 0x22, 0x22, 0x24, 0x21, 0x21, 0x23, 0x1e, 0x1e, 0x20, 0x1d, 0x1d, 0x1f, 0x1c, 0x1c, 0x1e, 0x31, 0x30, 0x32, 0x50, 0x4e, 0x54, 0x4e, 0x4c, 0x50, 0x4c, 0x4a, 0x4e, 0x3d, 0x3b, 0x3f, 0x38, 0x36, 0x3a, 0xff, 0xff, 0xff, 0x4, 0xb3, 0x69, 0x9b, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x10, 0x95, 0xb2, 0xd, 0x2c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0xed, 0x93, 0x29, 0x12, 0xc0, 0x30, 0xc, 0xc4, 0x7c, 0x3b, 0x67, 0xf3, 0xff, 0xdf, 0xb6, 0xe1, 0xce, 0x98, 0x15, 0x45, 0x58, 0xb3, 0x68, 0x5, 0x0, 0x80, 0x48, 0x21, 0x88, 0xb0, 0x41, 0x62, 0x51, 0xb, 0x50, 0x61, 0xda, 0xa, 0xb1, 0x79, 0xa9, 0x1, 0xc5, 0x8d, 0xe9, 0x1b, 0x60, 0x6b, 0x7d, 0xcc, 0x80, 0xd1, 0x9b, 0x31, 0x2, 0x8a, 0xf7, 0x67, 0x85, 0x3c, 0xdd, 0x5, 0x81, 0xb4, 0x8c, 0x75, 0x60, 0x14, 0x25, 0x20, 0xab, 0xf3, 0x24, 0xcc, 0x6a, 0x57, 0xb8, 0xc2, 0xff, 0x42, 0x76, 0xda, 0xf4, 0xf6, 0x69, 0x38, 0x69, 0x7a, 0x79, 0xbc, 0x49, 0xfe, 0x2f, 0x65, 0xd3, 0x2d, 0x45, 0xb, 0x5e, 0xbc, 0x3b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x4, 0x3, 0x0, 0x0, 0x0, 0x81, 0x54, 0x67, 0xc7, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0x26, 0x26, 0x28, 0x25, 0x25, 0x27, 0x24, 0x24, 0x26, 0x23, 0x23, 0x25, 0x22, 0x22, 0x24, 0x21, 0x21, 0x23, 0x1e, 0x1e, 0x20, 0x1d, 0x1d, 0x1f, 0x1c, 0x1c, 0x1e, 0x31, 0x30, 0x32, 0x50, 0x4e, 0x54, 0x4e, 0x4c, 0x50, 0x4c, 0x4a, 0x4e, 0x3d, 0x3b, 0x3f, 0x38, 0x36, 0x3a, 0xb3, 0xde, 0x6f, 0x4d, 0x0, 0x0, 0x0, 0x5a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0x14, 0x52, 0x82, 0x3, 0x45, 0x1, 0x20, 0x5f, 0xd9, 0x35, 0xd, 0xe, 0x42, 0x8c, 0x4, 0x18, 0x98, 0xcc, 0x2a, 0x66, 0xc2, 0x41, 0x7b, 0xb2, 0x2, 0x83, 0x70, 0xd6, 0x9e, 0xbb, 0x70, 0x70, 0x7a, 0x99, 0x21, 0x83, 0x48, 0xf5, 0xfb, 0xff, 0x70, 0xf0, 0x6f, 0xbb, 0x23, 0x83, 0x6a, 0xcf, 0x7f, 0x24, 0x70, 0x22, 0x88, 0x41, 0x6d, 0x2e, 0xb2, 0xc0, 0xcd, 0x24, 0x8a, 0x5, 0x46, 0x5, 0x30, 0x2, 0x19, 0x23, 0x1a, 0x30, 0x22, 0xa, 0x23, 0x2a, 0x31, 0x22, 0x1b, 0x23, 0x39, 0x0, 0x0, 0x8c, 0xb1, 0x80, 0xd2, 0x41, 0x59, 0x8c, 0x74, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_png[] = {
@@ -91,391 +91,395 @@ static const unsigned char graph_node_png[] = {
};
static const unsigned char graph_node_breakpoint_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x6, 0xf, 0x3b, 0x1c, 0xec, 0x64, 0x51, 0x75, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x8f, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0xd7, 0xbd, 0x9, 0xc0, 0x20, 0x10, 0x5, 0xe0, 0x53, 0x2c, 0x5d, 0x40, 0x74, 0x4, 0xf7, 0x9f, 0xc4, 0x11, 0x22, 0x2e, 0x60, 0x6f, 0x9a, 0x13, 0x4e, 0x21, 0x41, 0x50, 0x48, 0x91, 0x77, 0x95, 0xf8, 0xf3, 0x79, 0x62, 0xf5, 0x88, 0x36, 0x4b, 0xf5, 0x41, 0x2d, 0xf1, 0x22, 0x22, 0xbf, 0x78, 0x2e, 0x5b, 0x97, 0x2, 0xc9, 0xc3, 0xc, 0x2c, 0x95, 0xdc, 0x6f, 0x78, 0xce, 0x5b, 0x97, 0xd4, 0x42, 0x27, 0xd9, 0xba, 0x14, 0xac, 0x4b, 0xa1, 0x96, 0xd8, 0x24, 0x20, 0x9f, 0x41, 0x1d, 0x7b, 0xba, 0x59, 0xb6, 0xaf, 0xa7, 0x3d, 0x7e, 0x78, 0xdb, 0x54, 0xbc, 0x36, 0x74, 0xa7, 0x77, 0x7f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x4, 0xe4, 0xb7, 0xfc, 0xc8, 0x6b, 0x59, 0xce, 0x99, 0x39, 0x95, 0x71, 0xb4, 0x6b, 0x4b, 0x89, 0xf5, 0x44, 0x72, 0x3d, 0x93, 0x9d, 0x3f, 0xad, 0x1b, 0x54, 0xed, 0x49, 0xd3, 0x36, 0x45, 0x4f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x2, 0x3, 0x0, 0x0, 0x0, 0x6e, 0x13, 0x1f, 0x5, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf4, 0xe7, 0x2c, 0xf4, 0xe7, 0x2c, 0xec, 0x5a, 0x6b, 0x42, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe4, 0xd1, 0xf4, 0xeb, 0x59, 0x0, 0x0, 0x0, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x3, 0xb6, 0x55, 0xab, 0x26, 0x30, 0x88, 0x30, 0x0, 0x91, 0x42, 0xd6, 0x4a, 0xe, 0x6, 0x45, 0x7, 0x46, 0xf, 0x6, 0x25, 0x6, 0x86, 0xe, 0x20, 0x31, 0x4a, 0x80, 0x42, 0x3, 0x1c, 0x2e, 0xe0, 0x10, 0x82, 0x84, 0x15, 0x1c, 0x0, 0x0, 0x41, 0x2d, 0x2b, 0x21, 0xbb, 0xb7, 0x1a, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_close_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x93, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0x95, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x7b, 0xdb, 0x58, 0xa4, 0xa7, 0xe1, 0x47, 0xfe, 0x2c, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x15, 0xc9, 0x20, 0x1f, 0x52, 0xae, 0xdd, 0xd9, 0x2b, 0xe6, 0xe, 0x0, 0x60, 0x66, 0x59, 0x52, 0x82, 0x33, 0x92, 0x92, 0x99, 0x65, 0xec, 0x30, 0xc9, 0x4a, 0x72, 0x19, 0x95, 0x24, 0x25, 0x92, 0xb, 0xc9, 0x6a, 0x66, 0x19, 0x92, 0x26, 0x33, 0x7b, 0x92, 0x6c, 0x24, 0xd7, 0x10, 0xc2, 0xdc, 0xc1, 0x5f, 0x59, 0x8c, 0xf1, 0x32, 0xc, 0x42, 0x8, 0xb3, 0xb, 0x3b, 0xdb, 0xde, 0x24, 0x5f, 0x2e, 0xdc, 0x97, 0x3a, 0xb0, 0x91, 0xdc, 0x7e, 0xe1, 0xb3, 0x67, 0x66, 0x9f, 0xd6, 0xda, 0x69, 0x58, 0x90, 0x34, 0x95, 0x52, 0xee, 0x0, 0x6e, 0x0, 0x36, 0x0, 0x2b, 0x80, 0x6b, 0xad, 0xf5, 0xd1, 0x8b, 0x70, 0x6d, 0xb8, 0xf6, 0xfe, 0xd9, 0x18, 0x96, 0xe, 0x1f, 0xe, 0x38, 0xf6, 0x1a, 0x1f, 0x9f, 0xec, 0x40, 0x47, 0x56, 0x51, 0x84, 0x77, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x75, 0x90, 0xb5, 0x1, 0xc0, 0x30, 0x10, 0x3, 0x55, 0x1a, 0xbe, 0xc, 0x6e, 0xe6, 0xb5, 0xc3, 0x34, 0x4b, 0x98, 0xcc, 0xee, 0x7c, 0x4f, 0x92, 0x0, 0x70, 0x45, 0x19, 0x8c, 0x47, 0x19, 0x57, 0x37, 0x66, 0x1b, 0x6b, 0x74, 0x89, 0x32, 0xd6, 0xb0, 0xed, 0x2c, 0x51, 0xca, 0x6b, 0xb6, 0xb3, 0x41, 0x94, 0x0, 0xfe, 0x9f, 0x2c, 0x0, 0xa3, 0x64, 0x61, 0xa3, 0x6f, 0x66, 0xbd, 0xc6, 0x7f, 0xe9, 0x86, 0x3b, 0x5b, 0x34, 0x76, 0xa, 0xcf, 0xad, 0xe0, 0xaa, 0xbf, 0xa4, 0x4f, 0x5a, 0xa, 0x6d, 0x25, 0xba, 0x14, 0x37, 0x18, 0x8b, 0xe4, 0x0, 0x6f, 0xe9, 0x37, 0x83, 0x22, 0x73, 0x83, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_comment_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x19, 0x11, 0x2a, 0x1d, 0xd6, 0x78, 0x8b, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x1, 0x74, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x97, 0xbf, 0x4e, 0xc2, 0x50, 0x14, 0xc6, 0x7f, 0x6d, 0x91, 0x56, 0x1b, 0x90, 0x80, 0x2c, 0x44, 0xc2, 0xa0, 0x2e, 0xe, 0x3e, 0x3, 0x89, 0x93, 0xf1, 0x1d, 0x4c, 0x18, 0x4d, 0x1c, 0x7c, 0xb, 0x57, 0x7, 0x13, 0x47, 0x13, 0x77, 0x46, 0xe3, 0xc4, 0x4b, 0x98, 0x60, 0x4c, 0xd4, 0x81, 0x60, 0x58, 0x94, 0xff, 0x22, 0x2d, 0xd0, 0xd6, 0xe5, 0xde, 0x88, 0x8, 0x2, 0x35, 0x6e, 0xf7, 0x5b, 0x6e, 0x9a, 0x9c, 0xef, 0x77, 0xee, 0x39, 0x37, 0x1d, 0x3e, 0x8d, 0x2f, 0x69, 0x80, 0xe, 0x18, 0xe2, 0xd4, 0xf8, 0xae, 0x0, 0xf0, 0x1, 0x4f, 0x9c, 0x1, 0x63, 0x45, 0x3a, 0xb0, 0x6, 0x24, 0x81, 0x34, 0x10, 0x7, 0x56, 0x26, 0x0, 0x43, 0xa0, 0x3, 0xbc, 0x2, 0xd, 0xe0, 0x3, 0xf0, 0x65, 0x57, 0x1b, 0xd8, 0x5e, 0x8f, 0x25, 0x8e, 0x2d, 0xd3, 0x3a, 0x88, 0x46, 0xcd, 0x4d, 0xa6, 0x68, 0x30, 0x70, 0x5f, 0x1c, 0xd7, 0xb9, 0x6d, 0x77, 0x5b, 0x97, 0xc0, 0x13, 0xd0, 0xd3, 0x44, 0xa7, 0x5c, 0x32, 0x91, 0x3a, 0xdf, 0xca, 0xed, 0x1c, 0x16, 0x52, 0xdd, 0x2a, 0xbf, 0xe8, 0xaa, 0x1e, 0xcb, 0x3e, 0x57, 0x1e, 0x6f, 0x1a, 0xad, 0xfa, 0x29, 0x50, 0x91, 0x33, 0xa7, 0x4d, 0xd3, 0xca, 0xcf, 0x33, 0x3, 0x14, 0x52, 0xdd, 0xaa, 0x69, 0x5a, 0x79, 0x31, 0xaa, 0x21, 0x97, 0x65, 0x47, 0x8c, 0x88, 0xcd, 0x82, 0x12, 0xb5, 0x36, 0xa0, 0x49, 0x80, 0xc1, 0xf2, 0x32, 0x24, 0x20, 0x90, 0x4f, 0x12, 0x46, 0x3a, 0x7f, 0x94, 0x2, 0x28, 0x80, 0x2, 0x88, 0x5f, 0x7b, 0xfc, 0xe3, 0xec, 0xe1, 0x3d, 0x1b, 0x1a, 0x30, 0x1a, 0x7a, 0x1c, 0x65, 0xd8, 0x5f, 0xc4, 0x74, 0x5d, 0xa3, 0xa4, 0x5e, 0x41, 0x1, 0x14, 0x40, 0x1, 0x14, 0x40, 0x1, 0x14, 0x40, 0x1, 0xfe, 0x15, 0xa0, 0x4d, 0xc9, 0x88, 0x4b, 0xdf, 0xc0, 0xf, 0xe1, 0xf5, 0x25, 0xc0, 0x7, 0x1c, 0xcf, 0xf3, 0xdc, 0x45, 0x9d, 0xa2, 0xd6, 0x1, 0x7c, 0x5d, 0x44, 0xd9, 0xba, 0xe3, 0xf6, 0xcb, 0xc5, 0xa6, 0x5d, 0x9a, 0x67, 0x2e, 0x36, 0xed, 0x92, 0xe3, 0xf6, 0xcb, 0x40, 0x1d, 0xf0, 0x64, 0x72, 0x5d, 0x7, 0xf6, 0xe2, 0x76, 0xe2, 0xc2, 0x32, 0x57, 0x77, 0xd, 0xc3, 0xd0, 0x67, 0x74, 0xf6, 0x1d, 0xb7, 0x7f, 0xdf, 0xe9, 0xb5, 0x4e, 0x80, 0x3b, 0xa0, 0xad, 0x8d, 0x45, 0xb8, 0x38, 0x90, 0x1, 0x36, 0x0, 0x73, 0x46, 0xf8, 0x76, 0x81, 0x37, 0xa0, 0x26, 0x72, 0xb4, 0xa7, 0x4d, 0x2c, 0x34, 0x22, 0xf3, 0xe0, 0x8c, 0x9, 0x2, 0x31, 0xf2, 0x28, 0xe4, 0xe2, 0x7f, 0xea, 0x13, 0x64, 0x47, 0x6c, 0x83, 0x36, 0x6d, 0xd2, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x0, 0x78, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xd, 0x10, 0x17, 0x14, 0x18, 0x1d, 0x1a, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x10, 0x13, 0x35, 0x2f, 0x38, 0x96, 0x42, 0x2b, 0x0, 0x0, 0x0, 0x19, 0x17, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x77, 0x2f, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0xe, 0xb, 0x10, 0x24, 0x1e, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xb, 0x10, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x85, 0xbb, 0x9b, 0xdf, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x6, 0x8, 0x9, 0x2, 0xc, 0x1e, 0x33, 0x41, 0x46, 0xd, 0x31, 0x9a, 0xe3, 0xff, 0x5, 0x24, 0xb4, 0xff, 0xe2, 0x39, 0xf4, 0x44, 0xa, 0x47, 0xff, 0x42, 0x45, 0x3d, 0xf8, 0x2a, 0xcd, 0xff, 0x11, 0x3f, 0xd3, 0xfd, 0x2b, 0x31, 0x64, 0xfe, 0xeb, 0x0, 0x0, 0x0, 0x8d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xc8, 0x35, 0x62, 0x3, 0x41, 0x14, 0x4, 0xd1, 0xee, 0x21, 0x33, 0x33, 0xdb, 0xf7, 0xbf, 0x93, 0x99, 0x49, 0xcc, 0xd2, 0x7c, 0x2d, 0x53, 0xa6, 0x58, 0x5b, 0x59, 0x3d, 0x2, 0xc, 0x3, 0x20, 0x61, 0x20, 0x5c, 0x9, 0xc6, 0x74, 0x11, 0x20, 0x2c, 0x86, 0xbd, 0xec, 0x63, 0xa1, 0xd9, 0xa7, 0x47, 0x9a, 0x92, 0x7f, 0xda, 0x83, 0xa1, 0xcd, 0x60, 0xb2, 0xfa, 0xc7, 0x33, 0xf6, 0xb, 0xb0, 0x2e, 0xb4, 0xce, 0x2e, 0x17, 0x20, 0x2f, 0x82, 0x5d, 0x66, 0x2f, 0xb2, 0x20, 0xd4, 0x50, 0xc3, 0x19, 0x59, 0x1, 0xe3, 0xb, 0xa0, 0xa6, 0x34, 0xe7, 0x9c, 0x65, 0xa0, 0xe5, 0x9d, 0x7b, 0x3b, 0xe4, 0x38, 0x79, 0x27, 0xd2, 0xa2, 0xbb, 0x22, 0xd9, 0x8b, 0x7e, 0x43, 0x44, 0x5e, 0x8, 0x75, 0x67, 0x66, 0x1f, 0x3b, 0x0, 0x5a, 0x67, 0x7a, 0xfa, 0xe0, 0x9, 0xb8, 0x99, 0x3a, 0x44, 0xd8, 0xaf, 0xd7, 0x63, 0x10, 0x95, 0xe6, 0x1e, 0x57, 0xc1, 0x90, 0xf7, 0xdc, 0x9d, 0x9f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_comment_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x43, 0xbb, 0x7f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x9, 0x2, 0xe, 0x16, 0x22, 0xbe, 0xef, 0xc2, 0xe1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x1, 0x4a, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0xd7, 0xbf, 0x4b, 0xdb, 0x41, 0x1c, 0xc6, 0xf1, 0xd7, 0x37, 0x51, 0x4, 0x3, 0xa, 0xa2, 0x20, 0xd2, 0xe2, 0xe2, 0x64, 0x41, 0xdc, 0xdc, 0xac, 0xe0, 0x54, 0xdc, 0xb2, 0xe6, 0x2f, 0x10, 0x1a, 0xf0, 0x4f, 0x11, 0x22, 0xf8, 0x17, 0x64, 0xcd, 0x26, 0x9d, 0x1c, 0x74, 0x73, 0x13, 0x21, 0x4e, 0x2e, 0xa5, 0xa5, 0x14, 0xac, 0x82, 0x82, 0x62, 0xd0, 0x7c, 0xd3, 0xa1, 0x77, 0x18, 0x35, 0xfe, 0x48, 0xa4, 0xdb, 0x3d, 0x70, 0xdc, 0xf2, 0x79, 0xde, 0x77, 0xf7, 0x39, 0x38, 0xee, 0xc9, 0xdc, 0x2b, 0x43, 0x1, 0xc5, 0x30, 0x67, 0x1e, 0xaa, 0x83, 0x1c, 0xed, 0x30, 0x77, 0x74, 0x15, 0x15, 0x30, 0x8a, 0x9, 0x4c, 0x61, 0xc, 0xc3, 0x8f, 0x0, 0xb7, 0xb8, 0xc4, 0x29, 0xce, 0x71, 0x8d, 0x3c, 0xae, 0x5a, 0xc2, 0x5c, 0xa3, 0x5a, 0x59, 0xc7, 0x17, 0x7c, 0xd0, 0x5b, 0x3f, 0xf1, 0xad, 0x5c, 0xab, 0x6f, 0xe3, 0x4, 0x57, 0x59, 0x58, 0x69, 0xb6, 0x51, 0xad, 0x6c, 0x62, 0xed, 0x77, 0xf3, 0xf0, 0x87, 0x17, 0x34, 0xfd, 0x69, 0xf1, 0x23, 0x76, 0xca, 0xb5, 0xfa, 0x6, 0xbe, 0xc7, 0x33, 0x4f, 0x61, 0xe5, 0x35, 0x33, 0x84, 0x9a, 0x95, 0xe0, 0x29, 0xc6, 0x66, 0x95, 0xc2, 0x78, 0xab, 0x62, 0x7d, 0x16, 0x1, 0x45, 0xfd, 0xab, 0x18, 0x1, 0x9d, 0x78, 0x25, 0x83, 0xa8, 0xe0, 0x9d, 0x4a, 0x80, 0x4, 0x48, 0x80, 0x7f, 0x1a, 0xea, 0xf1, 0xda, 0xc, 0xe, 0x38, 0xd8, 0xdf, 0x5b, 0x7d, 0x8b, 0x69, 0x69, 0xf9, 0xf3, 0x6e, 0xba, 0x85, 0x4, 0x48, 0x80, 0x4, 0x48, 0x80, 0x4, 0x48, 0x80, 0x4, 0xf8, 0xaf, 0x80, 0xac, 0x47, 0x46, 0xec, 0x7b, 0x7, 0xf9, 0x0, 0xde, 0x3c, 0x2, 0x72, 0xdc, 0xa0, 0xd5, 0x87, 0xb9, 0x15, 0x3c, 0x79, 0x21, 0x44, 0xd9, 0x33, 0x34, 0xbb, 0x3f, 0x4f, 0xaf, 0x7c, 0xb0, 0x9a, 0xc1, 0xd3, 0x8e, 0xc9, 0x75, 0x1c, 0xb, 0x8d, 0x6a, 0x65, 0xb, 0xf3, 0x2f, 0x34, 0x37, 0xc7, 0x71, 0xb9, 0x56, 0xff, 0x8a, 0x23, 0x5c, 0x64, 0x5d, 0x11, 0x6e, 0xc, 0x33, 0x98, 0xc4, 0xc8, 0x33, 0xe1, 0xbb, 0x85, 0x3f, 0xf8, 0x15, 0x72, 0x74, 0x3b, 0x7b, 0xd4, 0xd0, 0xa1, 0x98, 0x7, 0x9f, 0xd9, 0x41, 0x27, 0x1c, 0xf9, 0x6e, 0xc0, 0xc6, 0x3f, 0xd5, 0x5f, 0x9d, 0x54, 0x4e, 0x15, 0xfd, 0xeb, 0xb4, 0x4f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x0, 0x6f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x96, 0x42, 0x2b, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77, 0x2f, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x5f, 0x8c, 0x8b, 0xc7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x6, 0x8, 0x9, 0x2, 0xc, 0x1e, 0x33, 0x41, 0x46, 0xd, 0x31, 0x9a, 0xe3, 0xff, 0x5, 0x24, 0xb4, 0xe2, 0x39, 0xf4, 0x44, 0xa, 0x47, 0x42, 0x45, 0x3d, 0xf8, 0x2a, 0xcd, 0x11, 0x3f, 0xd3, 0xfd, 0x2b, 0xb1, 0x1b, 0xa4, 0x4f, 0x0, 0x0, 0x0, 0x90, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xca, 0xb5, 0x75, 0xc4, 0x50, 0x0, 0x5, 0xd1, 0xf7, 0x49, 0xcc, 0xcc, 0xdc, 0x7f, 0x8b, 0x2b, 0xe6, 0xc8, 0xb1, 0x75, 0xc3, 0x39, 0x3, 0x80, 0x50, 0xc6, 0xc5, 0x84, 0x33, 0x4a, 0x30, 0x91, 0x64, 0x45, 0xd5, 0xf4, 0x89, 0xa6, 0x2a, 0xb2, 0x4, 0x48, 0x86, 0x69, 0xd9, 0xce, 0xc2, 0xb6, 0x4c, 0x43, 0x82, 0xeb, 0xf9, 0x4e, 0xb0, 0x71, 0x7c, 0xcf, 0x5, 0xf, 0xa3, 0xe0, 0x10, 0x85, 0x1c, 0x22, 0x76, 0xce, 0xe0, 0xc4, 0x2, 0x49, 0x7a, 0xd, 0x69, 0x2, 0xa1, 0xff, 0xb3, 0x70, 0xda, 0x42, 0x76, 0xf8, 0x73, 0xf8, 0xc2, 0x17, 0x92, 0xf4, 0x19, 0xf2, 0x6b, 0xc8, 0x13, 0xf0, 0xa2, 0x3c, 0x43, 0x59, 0x70, 0xb8, 0x55, 0x7d, 0x2c, 0x4e, 0x5d, 0xb9, 0x90, 0x9a, 0xb6, 0xeb, 0x9d, 0x45, 0xdf, 0xb5, 0x8d, 0x4, 0xd0, 0x66, 0x68, 0xf5, 0x74, 0xa2, 0xb7, 0x43, 0x43, 0x31, 0x91, 0x98, 0x48, 0x16, 0x82, 0x49, 0x78, 0x1b, 0x1, 0xf, 0xa7, 0x50, 0x68, 0x35, 0xb8, 0x84, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_default_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x39, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0xe, 0xb, 0x10, 0xe, 0xb, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x24, 0x1e, 0x27, 0x16, 0x12, 0x19, 0xff, 0xff, 0xff, 0x2b, 0x4d, 0xfd, 0x66, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x46, 0x47, 0x3f, 0x2b, 0x11, 0x3, 0xfd, 0xd3, 0xcd, 0x2a, 0x73, 0x45, 0xf8, 0x3d, 0x3f, 0x57, 0xda, 0x84, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x12, 0x7b, 0xbc, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x64, 0x2, 0x2, 0x46, 0x8, 0xc9, 0xcc, 0xc2, 0xca, 0xc6, 0xc0, 0x8f, 0x4, 0xd8, 0x39, 0x98, 0x59, 0x19, 0x50, 0x80, 0x0, 0x27, 0x17, 0xaa, 0x0, 0x83, 0x20, 0x37, 0x9a, 0x0, 0x3f, 0xd3, 0xc0, 0x8, 0xf0, 0xa0, 0x9, 0xf0, 0xf2, 0x61, 0x3a, 0x1d, 0xc3, 0x73, 0xe8, 0xde, 0x7, 0x0, 0x89, 0x4d, 0x2, 0xf2, 0x16, 0xd3, 0x74, 0x45, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0xe, 0xb, 0x10, 0xe, 0xb, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x24, 0x1e, 0x27, 0x16, 0x12, 0x19, 0x76, 0x9, 0xd2, 0x13, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x46, 0x47, 0x3f, 0x2b, 0x11, 0x3, 0xfd, 0xd3, 0xcd, 0x2a, 0x73, 0x45, 0xf8, 0x3d, 0x3f, 0x57, 0xda, 0x84, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x64, 0x2, 0x2, 0x46, 0x8, 0xc9, 0xcc, 0xc2, 0xca, 0xc6, 0xc0, 0x8f, 0x4, 0xd8, 0x39, 0x98, 0x59, 0x19, 0x50, 0x80, 0x0, 0x27, 0x17, 0x3, 0x2a, 0x10, 0xe4, 0x46, 0x13, 0xe0, 0x67, 0x1a, 0x18, 0x1, 0x1e, 0x34, 0x1, 0x5e, 0x3e, 0xc, 0xa7, 0x63, 0x78, 0xe, 0xc3, 0xfb, 0x0, 0x89, 0x4d, 0x2, 0xf2, 0xa2, 0x23, 0x3b, 0xc4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_default_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb7, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x9d, 0x91, 0x3d, 0x6a, 0x42, 0x61, 0x10, 0x45, 0xcf, 0x8c, 0x4f, 0x22, 0x7c, 0x58, 0x84, 0x14, 0x2e, 0xc0, 0xf5, 0x64, 0x17, 0xba, 0x3, 0x2d, 0x4, 0x41, 0x17, 0x96, 0x2a, 0x65, 0x5c, 0x43, 0x7a, 0xb, 0x53, 0xfa, 0xc3, 0x63, 0x9c, 0x6b, 0xf1, 0x4, 0xf9, 0x24, 0x31, 0x21, 0xb7, 0x1b, 0xe6, 0x14, 0x33, 0xe7, 0x1a, 0x80, 0xc, 0xc7, 0x1, 0xa7, 0x4b, 0x2, 0x49, 0x9a, 0xc0, 0x34, 0xc2, 0xbb, 0x11, 0xae, 0x58, 0x92, 0x4, 0x2d, 0x2d, 0x61, 0xb2, 0x99, 0xf8, 0x26, 0xfd, 0xaf, 0xe1, 0xdb, 0x62, 0xca, 0x89, 0x40, 0x88, 0x35, 0x13, 0xb6, 0x15, 0xb0, 0x7d, 0x99, 0x68, 0xfd, 0xae, 0xa2, 0x1e, 0x42, 0xcc, 0x9, 0x4a, 0x5, 0x94, 0x71, 0xd8, 0xfc, 0xa8, 0x67, 0xf5, 0x1d, 0x40, 0x34, 0xec, 0x2b, 0x60, 0xff, 0xd9, 0x48, 0x3, 0x1a, 0xdc, 0x79, 0x14, 0xbf, 0x3d, 0xf6, 0x4f, 0x80, 0xdf, 0x80, 0xfc, 0x2b, 0x60, 0x77, 0x16, 0x3a, 0x13, 0x76, 0x24, 0x48, 0x7, 0x28, 0x2c, 0x89, 0x6a, 0x1d, 0xc3, 0xe5, 0xae, 0x7c, 0xd0, 0x92, 0x3f, 0xa8, 0xb6, 0x53, 0xd9, 0xac, 0x5e, 0x39, 0x10, 0x8f, 0xcb, 0x4a, 0x3b, 0x5b, 0x67, 0x12, 0x80, 0xa7, 0xea, 0xbc, 0x6b, 0xdd, 0x17, 0xbe, 0x3f, 0x4f, 0x23, 0x27, 0x82, 0x63, 0x73, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x8a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x81, 0xff, 0x8c, 0xff, 0x99, 0xff, 0xb3, 0x2, 0x21, 0x3b, 0x4, 0x82, 0xd8, 0x40, 0x11, 0x46, 0x88, 0xa4, 0xf8, 0x7f, 0x49, 0x20, 0x14, 0xff, 0x2f, 0xa, 0x84, 0x8, 0xb6, 0xe0, 0x7f, 0x6e, 0xa0, 0x22, 0x90, 0x92, 0x92, 0xff, 0xd8, 0x60, 0xe5, 0x9b, 0xb6, 0x15, 0xff, 0x79, 0xc1, 0x4a, 0xb0, 0x83, 0x17, 0xc2, 0x29, 0xff, 0x1b, 0xe, 0x1, 0x4d, 0x61, 0xc6, 0xa1, 0x80, 0x5b, 0xf9, 0xf, 0x63, 0xe9, 0x77, 0xa0, 0x45, 0xac, 0xc, 0x38, 0x0, 0xd8, 0x72, 0xa0, 0x5b, 0xd8, 0xf1, 0x2b, 0x10, 0x27, 0xa4, 0x40, 0x92, 0x7c, 0x5, 0x8, 0x2b, 0xc8, 0x77, 0xe4, 0xb, 0xe1, 0xd2, 0x6f, 0x78, 0xbc, 0xf9, 0x87, 0x17, 0x18, 0x50, 0x7, 0x40, 0x1, 0x85, 0x23, 0xa8, 0x4b, 0xbf, 0x3, 0xc3, 0x91, 0x1f, 0x14, 0xd4, 0x78, 0x23, 0xb, 0x2d, 0xa0, 0xff, 0xb3, 0x23, 0x20, 0x22, 0xba, 0x1, 0x39, 0x96, 0x8a, 0xa5, 0x9b, 0x88, 0xa3, 0x56, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_position_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x6, 0xf, 0x3b, 0x3b, 0x49, 0x6e, 0xe4, 0x1e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x90, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0xd7, 0xbd, 0x9, 0xc0, 0x20, 0x10, 0x5, 0xe0, 0x53, 0x2c, 0xdd, 0x40, 0x47, 0x70, 0x7, 0x67, 0x77, 0x7, 0x47, 0x88, 0x1b, 0xd8, 0x9b, 0xe6, 0x84, 0x53, 0x48, 0x10, 0x14, 0x52, 0xe4, 0x5d, 0x25, 0xfe, 0x7c, 0x9e, 0x58, 0x3d, 0xa2, 0xcd, 0x52, 0x7d, 0x50, 0x63, 0xb8, 0x88, 0xc8, 0x2d, 0x9e, 0x2b, 0x36, 0x65, 0x4f, 0xf2, 0x30, 0x3, 0x4b, 0x25, 0xf7, 0x1b, 0x9e, 0x73, 0x36, 0x65, 0xb5, 0xd0, 0x49, 0xb1, 0x29, 0x7b, 0x9b, 0xb2, 0xaf, 0x31, 0x34, 0x9, 0xc8, 0x67, 0x50, 0xc7, 0x9e, 0x6e, 0x96, 0xed, 0xeb, 0x69, 0x8f, 0x1b, 0xde, 0x36, 0x15, 0xaf, 0xd, 0xdd, 0xe9, 0xdd, 0x5f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1f, 0x1, 0xe5, 0x2d, 0x3f, 0xf2, 0x5a, 0x91, 0x73, 0x66, 0x4e, 0x65, 0x1c, 0xed, 0xda, 0x52, 0x62, 0x3d, 0x91, 0x5c, 0xcf, 0x64, 0xe7, 0x4f, 0xeb, 0x6, 0x80, 0xff, 0x44, 0x93, 0xd4, 0xd9, 0xea, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x2, 0x3, 0x0, 0x0, 0x0, 0x6e, 0x13, 0x1f, 0x5, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf4, 0x3f, 0x2c, 0xf4, 0x3f, 0x2c, 0x1c, 0x3e, 0x10, 0xcd, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe4, 0xd1, 0xf4, 0xeb, 0x59, 0x0, 0x0, 0x0, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x3, 0xb6, 0x55, 0xab, 0x26, 0x30, 0x88, 0x30, 0x0, 0x91, 0x42, 0xd6, 0x4a, 0xe, 0x6, 0x45, 0x7, 0x46, 0xf, 0x6, 0x25, 0x6, 0x86, 0xe, 0x20, 0x31, 0x4a, 0x80, 0x42, 0x3, 0x1c, 0x2e, 0xe0, 0x10, 0x82, 0x84, 0x15, 0x1c, 0x0, 0x0, 0x41, 0x2d, 0x2b, 0x21, 0xbb, 0xb7, 0x1a, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_node_selected_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x17, 0xd, 0x4, 0x3b, 0xfa, 0x91, 0x2a, 0xb6, 0x0, 0x0, 0x3, 0x44, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x97, 0x3f, 0x68, 0xdc, 0x76, 0x14, 0xc7, 0xbf, 0xef, 0xa7, 0x9f, 0x7e, 0x3a, 0xdd, 0x39, 0xf6, 0xdd, 0x95, 0xb3, 0x3, 0xc1, 0x75, 0x1b, 0x70, 0xa, 0xe9, 0x98, 0x25, 0x93, 0x87, 0x52, 0x3a, 0x4, 0x2, 0xce, 0xe0, 0xd2, 0x34, 0x35, 0x94, 0x8e, 0x1d, 0xbc, 0xd5, 0x4b, 0xc7, 0x2e, 0x25, 0x63, 0x2, 0x5d, 0xa, 0xa5, 0xb1, 0x1b, 0x2, 0xf5, 0xd0, 0x40, 0xa0, 0x90, 0x10, 0x3a, 0x64, 0xca, 0x92, 0x31, 0x81, 0x24, 0xd0, 0xd2, 0x9a, 0x40, 0x2f, 0x17, 0xdf, 0x1f, 0xfb, 0x74, 0xf2, 0xe9, 0x27, 0xfd, 0x5e, 0x7, 0x49, 0xb6, 0x4e, 0xe7, 0xea, 0x86, 0x6e, 0xe5, 0x1e, 0xdc, 0x49, 0x42, 0xef, 0x7d, 0xde, 0xf7, 0x7d, 0xf5, 0x13, 0xe8, 0x47, 0xcc, 0x4c, 0x0, 0xc4, 0xbd, 0x7b, 0x4f, 0x9c, 0xb0, 0xdd, 0x71, 0xdb, 0xfb, 0x2d, 0xc7, 0xb0, 0x11, 0x5a, 0x7, 0x84, 0x4c, 0xd8, 0xb6, 0x62, 0x41, 0xc2, 0xd4, 0x67, 0x1b, 0x43, 0x59, 0xaf, 0xf9, 0x97, 0x2f, 0x5f, 0x18, 0x2, 0x30, 0xc4, 0xcc, 0xd6, 0xdd, 0x1f, 0xef, 0x9e, 0xea, 0x79, 0x83, 0x33, 0xed, 0x6e, 0xf7, 0x6c, 0xaf, 0xd7, 0x59, 0xe8, 0x7b, 0xfd, 0x72, 0x10, 0x4, 0x32, 0xb, 0x50, 0x4a, 0x85, 0x33, 0x95, 0x99, 0xc1, 0xdc, 0x5c, 0xad, 0x59, 0xaf, 0x56, 0x7f, 0x9f, 0xab, 0x94, 0x5f, 0xad, 0x7e, 0xbe, 0x7a, 0x40, 0x5b, 0x5b, 0xf7, 0x2b, 0x41, 0xbb, 0xf9, 0x6e, 0xa7, 0xd7, 0x5e, 0xb9, 0x72, 0x75, 0xe5, 0x86, 0x72, 0xa4, 0x85, 0x82, 0x8, 0x86, 0x61, 0xf4, 0xcb, 0x9d, 0x47, 0x1b, 0xb5, 0xb9, 0xfa, 0x23, 0x55, 0x5f, 0xf8, 0x43, 0xea, 0x4e, 0xb7, 0xdc, 0x7c, 0xf3, 0xfa, 0xdc, 0xc7, 0xeb, 0x1f, 0xdc, 0x64, 0x66, 0x71, 0xb8, 0x37, 0xbb, 0x2b, 0x1d, 0xb, 0x44, 0x23, 0x13, 0x80, 0x99, 0x11, 0xe, 0x23, 0x50, 0x65, 0x6f, 0x71, 0xf5, 0x93, 0x95, 0x9b, 0x3f, 0x6f, 0xff, 0xb6, 0x76, 0x9a, 0x9c, 0xa6, 0x8, 0x42, 0x5f, 0x79, 0xfd, 0x83, 0x79, 0xa7, 0x24, 0x5, 0xfc, 0xfa, 0x2e, 0x9, 0x42, 0xa8, 0xd, 0xc2, 0x20, 0x1a, 0xfd, 0x69, 0x3, 0x12, 0x4, 0xf8, 0xf5, 0x5d, 0xa7, 0x24, 0x85, 0xd7, 0x3f, 0x98, 0xf, 0x42, 0x5f, 0x9, 0xc3, 0x46, 0xc, 0xfc, 0x81, 0xb, 0x0, 0x91, 0x66, 0x30, 0x1b, 0x10, 0x0, 0x98, 0x6c, 0x7b, 0x80, 0xc0, 0x60, 0x66, 0x44, 0x21, 0x3, 0x0, 0x6, 0xfe, 0xc0, 0x35, 0x6c, 0x84, 0xd0, 0x5a, 0x53, 0x84, 0x88, 0x0, 0x80, 0x13, 0xd9, 0xcc, 0xc, 0x88, 0xb8, 0x10, 0x0, 0x40, 0x0, 0x1b, 0x0, 0xcc, 0x0, 0xc7, 0x39, 0x11, 0x22, 0xd2, 0x5a, 0x93, 0xb4, 0x6d, 0x9b, 0x11, 0x25, 0x89, 0x86, 0xc1, 0x20, 0x80, 0x18, 0xa0, 0xe3, 0xee, 0x47, 0xd0, 0xcc, 0x31, 0xad, 0x91, 0x79, 0xa3, 0x40, 0x4, 0x80, 0x91, 0xe6, 0xe5, 0x83, 0x73, 0x37, 0x64, 0xee, 0x2e, 0xd8, 0x24, 0x9, 0xc4, 0xc7, 0xa, 0xb2, 0x6a, 0x8a, 0x0, 0x1c, 0xf7, 0xce, 0x5e, 0xc4, 0xc5, 0xe6, 0x18, 0x92, 0x57, 0x36, 0x2, 0x30, 0x26, 0x33, 0x7b, 0xe2, 0x1e, 0x71, 0xe2, 0xb, 0x33, 0x68, 0xf2, 0x8, 0xd9, 0x16, 0x94, 0xd1, 0x13, 0xff, 0x9b, 0x49, 0xa, 0xc0, 0x6, 0x6c, 0x72, 0xf6, 0x8f, 0xbb, 0x58, 0xe0, 0x41, 0x32, 0x77, 0x22, 0x1a, 0xc9, 0xf2, 0x49, 0x87, 0x89, 0xcf, 0x8a, 0x14, 0xc4, 0x0, 0x93, 0x14, 0x66, 0xba, 0xd1, 0xf1, 0xec, 0xa6, 0x18, 0x60, 0xe2, 0xfa, 0x91, 0xde, 0xd9, 0xae, 0x34, 0xf9, 0x31, 0x52, 0xba, 0x1e, 0x28, 0x5d, 0x4c, 0x94, 0xfa, 0x99, 0xbc, 0xf, 0x45, 0xa, 0x4c, 0x5c, 0x38, 0xd6, 0xc9, 0xe0, 0xe8, 0x89, 0xe4, 0xad, 0x1d, 0x5f, 0xca, 0x9c, 0x7f, 0x15, 0x8b, 0x63, 0xdc, 0xc4, 0x7c, 0x8f, 0x8c, 0x91, 0xb9, 0x93, 0x71, 0xc0, 0xd7, 0xdf, 0x7c, 0xf5, 0xea, 0xd9, 0x8b, 0xa7, 0x85, 0x1d, 0xcf, 0x9f, 0x7b, 0x1f, 0xdf, 0xdf, 0xfa, 0x76, 0xf1, 0x44, 0xc0, 0xd9, 0xa5, 0x65, 0x58, 0xc2, 0x2e, 0x4, 0x2c, 0x2d, 0xbe, 0xf3, 0xef, 0xa, 0x3c, 0xaf, 0x8f, 0xde, 0x7e, 0xb7, 0x10, 0xe0, 0x79, 0xfd, 0x91, 0x6b, 0x81, 0xff, 0x18, 0x53, 0xc0, 0x14, 0x30, 0x5, 0x4c, 0x1, 0x53, 0xc0, 0x14, 0x30, 0x5, 0xfc, 0xff, 0x0, 0x5a, 0x6b, 0x82, 0x75, 0xe2, 0xe7, 0xcf, 0xc9, 0x91, 0xe6, 0x58, 0x19, 0x5, 0x16, 0x2c, 0x6, 0x0, 0x5b, 0xca, 0x89, 0xf5, 0x69, 0x4e, 0x5a, 0x23, 0x1c, 0xe5, 0x44, 0x8e, 0x52, 0x1, 0x0, 0x94, 0xdd, 0x99, 0x89, 0x80, 0x34, 0xc7, 0x51, 0x2a, 0x70, 0x94, 0x13, 0x49, 0x25, 0xdd, 0xa0, 0xe4, 0x96, 0x5b, 0xc3, 0x43, 0xcd, 0x1b, 0x9b, 0x9f, 0x5e, 0xbc, 0x71, 0x9d, 0x1e, 0xf, 0xfc, 0x3, 0xe8, 0x30, 0x1c, 0xd9, 0x74, 0xd9, 0x52, 0xa2, 0xec, 0x9e, 0xc2, 0xc6, 0xe6, 0xd5, 0x8b, 0xc3, 0x43, 0xcd, 0x25, 0xb7, 0xdc, 0x52, 0xd2, 0xd, 0x68, 0x6b, 0xeb, 0x7e, 0x65, 0xef, 0xaf, 0x97, 0xcb, 0xdd, 0xfd, 0xce, 0x87, 0x9f, 0x7d, 0x71, 0xe9, 0xba, 0xe3, 0xda, 0x85, 0x4e, 0xc, 0x7d, 0xcd, 0x3f, 0xfd, 0xf0, 0xeb, 0x66, 0x75, 0xb6, 0xf6, 0xf0, 0xad, 0xb7, 0x97, 0x5f, 0x12, 0x33, 0x5b, 0xb7, 0xbf, 0xbb, 0x3d, 0xdb, 0xea, 0x74, 0x97, 0x3a, 0xdd, 0xee, 0x7b, 0x3, 0xdf, 0x9b, 0xd7, 0x5a, 0xdb, 0xc6, 0x8c, 0x7e, 0xad, 0xa, 0x21, 0x60, 0xdb, 0xb6, 0x2e, 0xbb, 0x95, 0xd7, 0xb5, 0x6a, 0xf5, 0x79, 0xa3, 0x56, 0xfd, 0xf3, 0xda, 0x97, 0xd7, 0xf6, 0x29, 0xdd, 0xbd, 0x6f, 0x6f, 0x3f, 0x28, 0xf5, 0xff, 0x6e, 0x56, 0xb4, 0x19, 0x2a, 0x66, 0x73, 0xe2, 0xe3, 0x25, 0x12, 0xc6, 0x16, 0x4e, 0x30, 0x73, 0x7a, 0xc1, 0x5b, 0x5f, 0xff, 0xe8, 0x10, 0xc0, 0xd1, 0xf6, 0x4, 0xcc, 0x4c, 0x3b, 0x3b, 0x3b, 0xa2, 0xd1, 0x68, 0x14, 0x8e, 0xd0, 0x6a, 0xb5, 0x78, 0x6d, 0x6d, 0xcd, 0x10, 0xc5, 0xdb, 0xba, 0x7f, 0x0, 0xb2, 0x1f, 0xaf, 0x82, 0x62, 0x7a, 0x69, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x1, 0x5f, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb2, 0xb2, 0xcc, 0xae, 0xa0, 0xbb, 0x9c, 0x92, 0xa6, 0x9a, 0x91, 0xa4, 0x95, 0x8c, 0x9e, 0xaf, 0x9f, 0xaf, 0xa0, 0x94, 0xa5, 0x8e, 0x84, 0x95, 0x7f, 0x75, 0x84, 0x73, 0x6a, 0x78, 0x6d, 0x64, 0x72, 0xa2, 0xa2, 0xb9, 0x9c, 0x90, 0xa2, 0x8b, 0x81, 0x90, 0xdc, 0xda, 0xce, 0xe2, 0xe1, 0xd2, 0x9d, 0x91, 0xa9, 0x85, 0x7c, 0x8c, 0xdb, 0xd9, 0xce, 0xdb, 0xd9, 0xcd, 0xda, 0xce, 0xe0, 0xde, 0xd5, 0xe3, 0xdf, 0xd6, 0xe4, 0x97, 0x8d, 0xa0, 0x7a, 0x70, 0x7f, 0xdb, 0xd0, 0xdf, 0xdb, 0xd0, 0xe1, 0xda, 0xd0, 0xe1, 0x70, 0x67, 0x75, 0xd8, 0xcb, 0xde, 0xda, 0xcf, 0xdf, 0xdb, 0xce, 0xe1, 0xdb, 0xcf, 0xe1, 0xdb, 0xd0, 0xe0, 0xda, 0xcf, 0xe0, 0xd8, 0xcc, 0xde, 0x90, 0x87, 0x99, 0x6d, 0x67, 0x72, 0xd7, 0xcc, 0xdf, 0xda, 0xce, 0xdf, 0xd8, 0xcb, 0xdf, 0xd7, 0xca, 0xde, 0xd9, 0xcc, 0xdf, 0xd9, 0xcd, 0xdf, 0xd6, 0xc9, 0xdd, 0xd9, 0xcd, 0xde, 0xd6, 0xc8, 0xdc, 0xd5, 0xc8, 0xdc, 0xd7, 0xcb, 0xdd, 0xd7, 0xca, 0xdd, 0xd5, 0xc7, 0xdc, 0xd3, 0xc6, 0xdb, 0xd5, 0xc9, 0xdc, 0xd5, 0xc9, 0xdd, 0xd6, 0xc9, 0xdc, 0xd4, 0xc6, 0xdb, 0xd3, 0xc5, 0xdb, 0xd5, 0xc8, 0xdb, 0xd4, 0xc8, 0xdc, 0xd3, 0xc4, 0xd9, 0xd4, 0xc6, 0xda, 0xd2, 0xc3, 0xd9, 0xd3, 0xc5, 0xda, 0xd2, 0xc5, 0xd9, 0xd3, 0xc5, 0xd9, 0xd2, 0xc5, 0xda, 0xd1, 0xc2, 0xd9, 0xd2, 0xc4, 0xd8, 0xd2, 0xc4, 0xd9, 0xd0, 0xc2, 0xd9, 0xd0, 0xc1, 0xd7, 0xd0, 0xc2, 0xd7, 0xd0, 0xc2, 0xd8, 0xd1, 0xc2, 0xd7, 0xcf, 0xc1, 0xd7, 0xd0, 0xc2, 0xd6, 0xcf, 0xc1, 0xd6, 0xcf, 0xc2, 0xd7, 0xcf, 0xc0, 0xd7, 0xce, 0xbf, 0xd6, 0xce, 0xc0, 0xd5, 0xce, 0xc0, 0xd6, 0xce, 0xbf, 0xd5, 0xcd, 0xbf, 0xd5, 0xcd, 0xbe, 0xd5, 0xcd, 0xbe, 0xd4, 0xcc, 0xbd, 0xd5, 0xcc, 0xbd, 0xd4, 0xcc, 0xbc, 0xd4, 0x47, 0x40, 0x4a, 0x1d, 0x1a, 0x1f, 0x69, 0x5f, 0x6f, 0x4a, 0x42, 0x4f, 0x5e, 0x54, 0x63, 0x3b, 0x34, 0x3f, 0x5e, 0x55, 0x63, 0x63, 0x59, 0x67, 0x77, 0x6d, 0x7b, 0x6d, 0x62, 0x73, 0x7f, 0x76, 0x85, 0xdb, 0xd9, 0xcd, 0xdb, 0xd8, 0xcd, 0x6d, 0x62, 0x74, 0x8f, 0x84, 0x94, 0x7f, 0x76, 0x83, 0xdb, 0xd8, 0xcd, 0xa4, 0x95, 0xa4, 0x7e, 0x74, 0x84, 0x74, 0x6b, 0x79, 0x6f, 0x66, 0x74, 0x96, 0x8a, 0xa2, 0x91, 0x88, 0x9b, 0x0, 0x0, 0x0, 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xbf, 0xf0, 0xc9, 0xec, 0x71, 0x0, 0x0, 0x0, 0x75, 0x74, 0x52, 0x4e, 0x53, 0x1, 0x3, 0xa, 0x13, 0x1a, 0x1c, 0x1d, 0x10, 0x2b, 0x4d, 0x64, 0x6e, 0x72, 0xb, 0x2c, 0x6a, 0xfc, 0xff, 0x15, 0x52, 0xfd, 0xff, 0xe2, 0xe2, 0xe2, 0x1b, 0x68, 0xe2, 0xe2, 0xe2, 0x71, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0x1e, 0x72, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0x6b, 0xc7, 0x56, 0xfe, 0xff, 0xc7, 0x30, 0x74, 0xfe, 0x11, 0x57, 0x6d, 0x72, 0x16, 0x1c, 0x0, 0x3, 0x4, 0x35, 0xf5, 0x4, 0x26, 0x0, 0x0, 0x1, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0xd0, 0x35, 0x82, 0x1c, 0x31, 0x14, 0x84, 0xe1, 0xbf, 0xa4, 0xd7, 0x32, 0x33, 0xb3, 0xf, 0x63, 0x8e, 0xcd, 0x10, 0xcd, 0x99, 0x1c, 0x3a, 0x75, 0xe8, 0xcc, 0xbe, 0x8e, 0x99, 0x79, 0xb9, 0x49, 0x6f, 0x49, 0xd3, 0xcb, 0x7b, 0x82, 0xa9, 0xac, 0x3e, 0xb1, 0xc, 0xad, 0x4, 0xf0, 0x95, 0x98, 0xd2, 0x6, 0x68, 0xec, 0x60, 0xa9, 0xac, 0x52, 0xb2, 0x6a, 0xf3, 0x92, 0x3d, 0x9a, 0xdf, 0x2f, 0x39, 0x20, 0xf7, 0xb9, 0x7d, 0x6e, 0xbf, 0xcf, 0x62, 0xea, 0xaa, 0x96, 0x24, 0x69, 0xce, 0xbe, 0xd9, 0x55, 0x4d, 0xef, 0x5b, 0xd8, 0xbb, 0x90, 0x9a, 0xa6, 0x39, 0x21, 0xf6, 0x5d, 0xb5, 0x77, 0xa9, 0x8a, 0x7, 0x35, 0xd5, 0xc0, 0x19, 0x32, 0x9f, 0xcf, 0x1b, 0x10, 0x3d, 0x9c, 0x1, 0x20, 0x2, 0x6, 0x84, 0xbf, 0x24, 0x9a, 0x44, 0x73, 0xac, 0x80, 0x4e, 0x80, 0x5c, 0x4e, 0x28, 0x60, 0x2, 0xc9, 0x3d, 0xa8, 0x40, 0x25, 0xe6, 0x0, 0xe, 0xe4, 0x2, 0x51, 0x1c, 0x2, 0x40, 0x5, 0x82, 0xa4, 0x2c, 0x3c, 0x76, 0xc3, 0x12, 0x51, 0xfb, 0x9e, 0xba, 0xdb, 0x3b, 0x6c, 0x2a, 0x45, 0xd8, 0xaf, 0x3c, 0x86, 0x3e, 0x57, 0x31, 0xc7, 0x7e, 0x98, 0x51, 0x25, 0x39, 0xca, 0x15, 0x1a, 0x3, 0x2, 0x8f, 0xc0, 0x70, 0xa, 0x20, 0x1c, 0x2f, 0x10, 0x87, 0x2f, 0x1c, 0x66, 0xec, 0xe, 0x1b, 0x33, 0x81, 0xd, 0x99, 0xc0, 0x55, 0xfd, 0x8, 0x5e, 0x4a, 0xe0, 0x82, 0x1b, 0xf3, 0x68, 0xc, 0x62, 0x7e, 0xaf, 0x4d, 0xdf, 0x79, 0x15, 0xf2, 0x30, 0xe3, 0xfa, 0x1b, 0xab, 0xc3, 0x3d, 0x59, 0xe3, 0x99, 0xa0, 0xe4, 0xf7, 0xbc, 0xb6, 0xd6, 0xa4, 0x97, 0x65, 0xc6, 0x63, 0xf7, 0xd6, 0x66, 0x62, 0x1f, 0x9f, 0xe9, 0x5, 0x30, 0x72, 0xef, 0xe2, 0x8c, 0xf9, 0xf3, 0x83, 0x23, 0xbd, 0x3e, 0xf, 0x2c, 0x6e, 0xbb, 0xf7, 0xff, 0x5, 0x5f, 0xfe, 0xb3, 0x14, 0x31, 0xf4, 0x31, 0x33, 0xfa, 0x41, 0xd3, 0xe9, 0xe7, 0x22, 0x6, 0x0, 0xb4, 0xb3, 0x74, 0xef, 0x4f, 0xde, 0x59, 0x95, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_port_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x6, 0x0, 0x0, 0x0, 0x8d, 0x32, 0xcf, 0xbd, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xc6, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x6d, 0x90, 0x3d, 0x4e, 0xc4, 0x30, 0x14, 0x84, 0xbf, 0xb1, 0xa8, 0x92, 0x48, 0x39, 0x46, 0xe2, 0x9a, 0x9f, 0x12, 0xc1, 0xbd, 0x16, 0x25, 0x4b, 0x41, 0xb, 0x67, 0xa1, 0xa7, 0xa2, 0x63, 0xa1, 0x76, 0x94, 0x5b, 0x58, 0x72, 0x52, 0x3e, 0xd3, 0xc4, 0x11, 0xda, 0xe5, 0xab, 0x46, 0xa3, 0xd1, 0x68, 0xde, 0x13, 0x1b, 0x21, 0x84, 0x7, 0x49, 0x3, 0x70, 0xbb, 0x59, 0x5f, 0xc0, 0x5b, 0xdf, 0xf7, 0xef, 0x0, 0x2, 0x98, 0xa6, 0xe9, 0x0, 0x1c, 0x1, 0xc7, 0x19, 0x39, 0xe7, 0x67, 0xef, 0xfd, 0xa0, 0xad, 0xe9, 0x3, 0x70, 0x6d, 0xdb, 0x52, 0xd7, 0x35, 0x0, 0xcb, 0xb2, 0x10, 0x63, 0x4, 0x30, 0xe7, 0xdc, 0xe3, 0x95, 0xa4, 0xb1, 0x84, 0x9a, 0xa6, 0xd9, 0x9b, 0x8a, 0x8e, 0x31, 0x3a, 0x33, 0x1b, 0x1d, 0x70, 0xd, 0xec, 0x4d, 0x7f, 0xa9, 0xaa, 0xaa, 0xc8, 0x1b, 0x7, 0xe4, 0x8b, 0xc4, 0x25, 0xd9, 0x1, 0x3f, 0x65, 0xd3, 0x39, 0xeb, 0xba, 0x16, 0xf9, 0xed, 0x80, 0xd7, 0x6d, 0xb, 0x29, 0x25, 0xcc, 0xc, 0x33, 0x23, 0xa5, 0xb4, 0x1f, 0x23, 0x69, 0x14, 0x40, 0x8, 0xe1, 0x28, 0xe9, 0xf0, 0xcf, 0x7b, 0x2c, 0xe7, 0xfc, 0xe4, 0xbd, 0x7f, 0x51, 0x71, 0xe6, 0x79, 0xbe, 0x37, 0xb3, 0x1, 0xb8, 0xdb, 0x76, 0x9f, 0x24, 0x8d, 0x5d, 0xd7, 0x7d, 0x2, 0xfc, 0x2, 0xfb, 0x83, 0x50, 0x87, 0x89, 0x31, 0xee, 0x78, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xce, 0x41, 0xa, 0x83, 0x30, 0x10, 0x85, 0xe1, 0xb9, 0x98, 0xe2, 0x9, 0x3c, 0x50, 0xe9, 0xc6, 0x83, 0x45, 0x7b, 0x8b, 0xfc, 0x7a, 0x1, 0xd7, 0x49, 0xba, 0xd, 0xd3, 0x79, 0xd0, 0x16, 0x41, 0xfe, 0x6c, 0xe6, 0x83, 0xc0, 0x33, 0x8f, 0xf2, 0xc4, 0xc6, 0x3b, 0x5a, 0x99, 0x75, 0xc7, 0xe3, 0x49, 0xc7, 0x7f, 0xe5, 0x25, 0x30, 0x4f, 0xa2, 0xd3, 0x6b, 0x74, 0x8a, 0xfb, 0x31, 0x1a, 0x2f, 0x51, 0xfb, 0x26, 0x66, 0x35, 0x1a, 0x5e, 0xff, 0x58, 0x84, 0xd5, 0xa8, 0x37, 0x2c, 0xc6, 0x76, 0xfb, 0x9e, 0x8c, 0x19, 0x17, 0x97, 0x48, 0x44, 0xdf, 0x7, 0xad, 0x5c, 0x2e, 0x93, 0x7a, 0x7e, 0x68, 0x67, 0x74, 0x8c, 0x24, 0x1a, 0x95, 0xb4, 0xf, 0xba, 0x3f, 0x56, 0x94, 0xa6, 0x72, 0xc9, 0xf9, 0xda, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hseparator_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x3, 0x11, 0xc, 0x4c, 0xf2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x64, 0x60, 0x60, 0xc2, 0x40, 0x8c, 0xc, 0x0, 0x0, 0xc7, 0x0, 0xf, 0xf5, 0x92, 0x2f, 0xa7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x64, 0x60, 0x60, 0xc2, 0x40, 0x8c, 0xc, 0x0, 0x0, 0xc7, 0x0, 0xf, 0xf5, 0x92, 0x2f, 0xa7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hslider_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x4e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xff, 0xff, 0xff, 0x5f, 0xd6, 0x94, 0x4d, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x68, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x1a, 0x96, 0x95, 0x6b, 0xe2, 0xd5, 0x49, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x19, 0xec, 0x6e, 0xb5, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x85, 0xce, 0xdd, 0xe, 0x80, 0x20, 0x8, 0x5, 0x60, 0x54, 0xb4, 0x22, 0xb5, 0x34, 0x7f, 0x7a, 0xff, 0x27, 0x8d, 0xad, 0xd6, 0x6a, 0x5c, 0xf8, 0xdd, 0xc1, 0x6, 0xe7, 0x0, 0x8c, 0xa9, 0x1f, 0x9e, 0xb5, 0x41, 0xeb, 0x26, 0xe6, 0x2c, 0x1a, 0xad, 0x40, 0xcf, 0xb, 0xad, 0xf9, 0x60, 0x79, 0xa5, 0x65, 0xd6, 0x60, 0x7c, 0x28, 0xb5, 0x75, 0xd6, 0x6a, 0x9, 0xde, 0x0, 0x52, 0xe9, 0xe7, 0xa3, 0x17, 0x42, 0xb0, 0xb1, 0x9e, 0xaf, 0x1a, 0xad, 0x5c, 0x88, 0x93, 0x6d, 0xff, 0x3e, 0xdd, 0x37, 0x8e, 0x4d, 0x14, 0xef, 0xd8, 0x48, 0x89, 0x63, 0x45, 0x31, 0x51, 0x7d, 0xe8, 0x2, 0xf5, 0xf, 0x9, 0x67, 0xd9, 0x88, 0x8f, 0x5b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x57, 0x2e, 0xcb, 0x70, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x68, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x1a, 0x96, 0x95, 0x6b, 0xe2, 0xd5, 0x49, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x4f, 0x83, 0x11, 0x3, 0x1, 0x10, 0xcc, 0x39, 0xef, 0xfe, 0xb, 0x7d, 0xdb, 0xc6, 0x8e, 0x8e, 0xb, 0xf8, 0x9d, 0x70, 0x1d, 0x9c, 0x46, 0x2d, 0xcc, 0x18, 0xea, 0x11, 0x80, 0xda, 0xb7, 0x36, 0xe, 0xf2, 0xbe, 0x2f, 0x80, 0x1c, 0xb0, 0xe5, 0xa2, 0x1f, 0xa5, 0xc0, 0xea, 0x12, 0x2c, 0x4, 0x75, 0x52, 0x80, 0x38, 0x46, 0x2b, 0x65, 0x9d, 0xa7, 0x97, 0xc1, 0xf5, 0x25, 0x82, 0x7a, 0x47, 0x4a, 0x83, 0xac, 0x93, 0x33, 0x8f, 0x83, 0xaa, 0xb2, 0xb4, 0xb8, 0x18, 0xbb, 0x58, 0xff, 0x4e, 0xdb, 0x1, 0xc3, 0xf1, 0x34, 0x3b, 0x7e, 0xbc, 0xb3, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hslider_grabber_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0x3f, 0x4b, 0xc3, 0x40, 0x18, 0xc7, 0xf1, 0xef, 0x25, 0xad, 0x89, 0xa9, 0x70, 0x83, 0x43, 0x5d, 0xc4, 0x21, 0x6e, 0x4a, 0x7, 0x47, 0xdf, 0x83, 0x53, 0x16, 0x17, 0xd7, 0x4e, 0xbe, 0x2, 0x5f, 0x85, 0x83, 0xa0, 0xb8, 0x38, 0xb8, 0x88, 0xd0, 0x51, 0x5d, 0x1c, 0x1c, 0x1c, 0x1c, 0x2a, 0xa2, 0xe8, 0x22, 0x2d, 0x82, 0x2d, 0x88, 0x54, 0xed, 0x3f, 0x1b, 0x9a, 0x78, 0x49, 0x1c, 0x9a, 0x54, 0x4f, 0x5, 0x6f, 0x3a, 0xee, 0xf9, 0xf0, 0x3c, 0x3f, 0x9e, 0x83, 0x7f, 0x8e, 0x18, 0xdf, 0x4c, 0x1c, 0x24, 0x5, 0x60, 0x40, 0x17, 0x9f, 0x48, 0x7, 0x26, 0xd3, 0xe5, 0x55, 0xd7, 0x93, 0x25, 0xe8, 0xde, 0xd4, 0x2b, 0xbb, 0x7, 0xbc, 0x8e, 0x88, 0x99, 0x82, 0xa9, 0xf2, 0xda, 0xe2, 0x86, 0x58, 0x78, 0xb7, 0x87, 0xf6, 0xc4, 0xdc, 0xcc, 0xd2, 0x6c, 0xfb, 0xf2, 0x8e, 0x10, 0xc0, 0x48, 0x81, 0x74, 0x3d, 0x55, 0xf4, 0x51, 0x28, 0x7c, 0x54, 0xd1, 0xf5, 0x90, 0xa3, 0x42, 0x6, 0xa, 0xb2, 0x14, 0x90, 0x0, 0x90, 0x10, 0x20, 0x4b, 0x14, 0x74, 0x20, 0x62, 0xf1, 0x3d, 0x7b, 0x24, 0xb2, 0x74, 0x19, 0x8, 0x83, 0x96, 0x39, 0x2e, 0xb, 0x82, 0x37, 0x94, 0xe, 0x6, 0xbd, 0xdb, 0xfc, 0x18, 0xe4, 0x49, 0x9e, 0xf0, 0x75, 0xd0, 0xbf, 0x3e, 0xb6, 0x22, 0x23, 0x7d, 0x9a, 0x4c, 0xce, 0xf6, 0xe8, 0xe9, 0x20, 0xb8, 0xaa, 0x6, 0xcd, 0x1c, 0x0, 0x39, 0x3e, 0x1e, 0x4f, 0xce, 0x7f, 0x76, 0x88, 0x1f, 0x1a, 0xcf, 0xa7, 0xe, 0x6, 0x6, 0xe, 0x8d, 0x23, 0xd5, 0x22, 0xd6, 0x41, 0x42, 0x77, 0x6b, 0x33, 0xaa, 0x59, 0x58, 0xc4, 0xf5, 0x9d, 0xed, 0x6c, 0xc0, 0xd7, 0x26, 0x21, 0xe, 0x7, 0x9d, 0xda, 0xf2, 0x8a, 0x1d, 0x1f, 0xae, 0xdf, 0x57, 0x19, 0xfe, 0x6, 0xa0, 0x9a, 0x2f, 0xf3, 0xed, 0xfe, 0xc5, 0x7e, 0x85, 0xce, 0x5f, 0xbf, 0x39, 0xca, 0x67, 0x21, 0x18, 0x66, 0x3b, 0x0, 0xf8, 0x4, 0x7e, 0x5c, 0x62, 0x33, 0x51, 0xf0, 0xbb, 0xff, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xf3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x1e, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x96, 0x96, 0xd7, 0x79, 0x70, 0xc6, 0xfb, 0x19, 0xef, 0x3b, 0xf, 0xa6, 0xe5, 0x31, 0x88, 0xa1, 0x2b, 0xe1, 0x4d, 0xcb, 0x9b, 0xf4, 0xa2, 0xef, 0x7f, 0x3b, 0x10, 0xf6, 0xfd, 0x9f, 0xf4, 0x2, 0xa8, 0x84, 0x17, 0x55, 0x81, 0x4c, 0xe7, 0xc1, 0xbe, 0xff, 0x2d, 0xff, 0x9b, 0x81, 0xb0, 0x5, 0xa8, 0xa4, 0xf3, 0x20, 0xd0, 0x22, 0x14, 0xa0, 0x3e, 0xe3, 0x7d, 0x3b, 0x50, 0x12, 0xc, 0x81, 0xa6, 0xcc, 0x78, 0xf, 0x74, 0xb, 0xa, 0xd0, 0x98, 0xf6, 0x1, 0x59, 0xc1, 0xd4, 0xf, 0xc, 0x1a, 0xa8, 0xa, 0x94, 0xfa, 0x6f, 0x77, 0xc1, 0x15, 0x74, 0xfc, 0xef, 0xbb, 0xc7, 0xa0, 0x82, 0xaa, 0x40, 0xbc, 0x71, 0x7d, 0x3f, 0x5c, 0x41, 0xef, 0xff, 0xde, 0xa3, 0xc, 0x52, 0xa8, 0xa, 0xb8, 0x82, 0x52, 0xa7, 0xfd, 0x69, 0x5, 0x4b, 0xb7, 0xfe, 0x9f, 0xf6, 0xcf, 0x37, 0x85, 0x81, 0x7, 0x2d, 0x1c, 0x14, 0xd, 0xfb, 0x1f, 0x74, 0x82, 0x15, 0x74, 0xfe, 0x9f, 0xf8, 0x80, 0x45, 0x83, 0x81, 0x9, 0x55, 0x1, 0x23, 0x83, 0x48, 0xc5, 0x9c, 0xc9, 0xff, 0x5b, 0x81, 0x70, 0xf2, 0xff, 0x92, 0xa9, 0xc, 0xc2, 0x98, 0x41, 0xcd, 0xca, 0xa3, 0x33, 0xe1, 0x76, 0xcf, 0xff, 0x9e, 0xff, 0x13, 0xef, 0xf0, 0xe8, 0x30, 0xb0, 0x62, 0x8b, 0xd, 0x6e, 0xb, 0xff, 0x39, 0x5f, 0xe6, 0x7c, 0x77, 0x8, 0x45, 0xd8, 0x8f, 0x61, 0x4d, 0x51, 0x71, 0x55, 0x2d, 0x83, 0x18, 0x90, 0x85, 0x3, 0xb0, 0x30, 0x70, 0x3, 0x75, 0xb3, 0x20, 0xb, 0x1, 0x0, 0x86, 0xe, 0x79, 0x54, 0x16, 0xbe, 0x69, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hslider_grabber_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x7, 0xa, 0x13, 0x2f, 0x7, 0x5e, 0x49, 0xee, 0x14, 0x0, 0x0, 0x0, 0x1d, 0x69, 0x54, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x64, 0x2e, 0x65, 0x7, 0x0, 0x0, 0x0, 0xea, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x20, 0x1a, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x66, 0x9c, 0xe7, 0x7a, 0xd0, 0xe7, 0xbd, 0xcf, 0x7b, 0xd7, 0x83, 0xc6, 0x79, 0xc, 0x62, 0xe8, 0x4a, 0x78, 0x8d, 0xf3, 0x3c, 0x5f, 0xb8, 0xff, 0x77, 0x1, 0x42, 0xf7, 0xff, 0x9e, 0x2f, 0x80, 0x4a, 0x78, 0x51, 0x15, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x85, 0xee, 0xff, 0x5d, 0xf, 0x2, 0x2d, 0x42, 0x1, 0xea, 0x3e, 0xef, 0x5d, 0xe0, 0xa, 0x5c, 0xfe, 0xfb, 0xbc, 0x7, 0xba, 0x5, 0x5, 0x68, 0x78, 0x7f, 0x40, 0x56, 0xe0, 0xfd, 0x81, 0x41, 0x3, 0x55, 0x81, 0x92, 0xc7, 0x6d, 0x57, 0x24, 0x5, 0xee, 0xf7, 0x18, 0x54, 0x50, 0x15, 0x88, 0x3b, 0xae, 0xf7, 0x40, 0x72, 0x83, 0xfb, 0x51, 0x6, 0x29, 0x54, 0x5, 0x5c, 0x9a, 0xa9, 0xde, 0x7f, 0x9c, 0xc1, 0xd2, 0xce, 0xff, 0xbd, 0xff, 0xa9, 0xa7, 0x30, 0xf0, 0xa0, 0x85, 0x83, 0xa0, 0xa1, 0xc7, 0x3, 0x88, 0x25, 0xae, 0xff, 0x3d, 0x1f, 0x30, 0x69, 0x30, 0x30, 0xa1, 0x2a, 0x60, 0x64, 0x10, 0xb1, 0x99, 0xe3, 0x5, 0xd4, 0xed, 0xfc, 0xdf, 0xeb, 0xbf, 0xd5, 0x54, 0x6, 0x61, 0xcc, 0xa0, 0x66, 0x65, 0xd3, 0xf1, 0xb8, 0xed, 0xf6, 0xdf, 0xed, 0xbf, 0xe7, 0x1d, 0x36, 0x1d, 0x6, 0x56, 0x6c, 0xb1, 0xc1, 0x2d, 0xe3, 0xef, 0xf7, 0xc5, 0xef, 0xbb, 0x42, 0x28, 0xba, 0xfd, 0x48, 0xd6, 0x58, 0x16, 0xdb, 0xd6, 0x2, 0xe3, 0x81, 0x11, 0x57, 0x8c, 0xb2, 0x30, 0x70, 0x3, 0x75, 0xb3, 0x20, 0xb, 0x1, 0x0, 0x4, 0x5c, 0x63, 0x9b, 0x17, 0x86, 0x76, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xe7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x1e, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x66, 0x9c, 0xe7, 0x7a, 0xd0, 0xe7, 0xbd, 0xcf, 0x7b, 0xd7, 0x83, 0xc6, 0x79, 0xc, 0x62, 0xe8, 0x4a, 0x78, 0x8d, 0xf3, 0x3c, 0x5f, 0xb8, 0xff, 0x77, 0x1, 0x42, 0xf7, 0xff, 0x9e, 0x2f, 0x80, 0x4a, 0x78, 0x51, 0x15, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x81, 0x40, 0x25, 0xae, 0x7, 0x81, 0x16, 0xa1, 0x0, 0x75, 0x9f, 0xf7, 0x2e, 0x30, 0x5, 0x40, 0x53, 0x7c, 0xde, 0x3, 0xdd, 0x82, 0x2, 0x34, 0xbc, 0x3f, 0x20, 0x2b, 0xf0, 0xfe, 0xc0, 0xa0, 0x81, 0xaa, 0x40, 0xc9, 0xe3, 0xb6, 0x2b, 0x92, 0x2, 0xf7, 0x7b, 0xc, 0x2a, 0xa8, 0xa, 0xc4, 0x1d, 0xd7, 0x7b, 0x20, 0xb9, 0xc1, 0xfd, 0x28, 0x83, 0x14, 0xaa, 0x2, 0x2e, 0xcd, 0x54, 0xef, 0x3f, 0xce, 0x60, 0x69, 0xe7, 0xff, 0xde, 0xff, 0xd4, 0x53, 0x18, 0x78, 0xd0, 0xc2, 0x41, 0xd0, 0xd0, 0xe3, 0x1, 0xc4, 0x12, 0xd7, 0xff, 0x9e, 0xf, 0x98, 0x34, 0x18, 0x98, 0x50, 0x15, 0x30, 0x32, 0x88, 0xd8, 0xcc, 0xf1, 0xfa, 0xef, 0xc, 0x84, 0x5e, 0xff, 0xad, 0xa6, 0x32, 0x8, 0x63, 0x6, 0x35, 0x2b, 0x9b, 0x8e, 0xc7, 0x6d, 0xb7, 0xff, 0x6e, 0xff, 0x3d, 0xef, 0xb0, 0xe9, 0x30, 0xb0, 0x62, 0x8b, 0xd, 0x6e, 0x19, 0x7f, 0xbf, 0x2f, 0x7e, 0xdf, 0x15, 0x42, 0x11, 0xf6, 0x63, 0x58, 0x63, 0x59, 0x6c, 0x5b, 0xcb, 0x20, 0x6, 0x64, 0xe1, 0x0, 0x2c, 0xc, 0xdc, 0x40, 0xdd, 0x2c, 0xc8, 0x42, 0x0, 0x4, 0x5c, 0x63, 0x9b, 0xfc, 0xae, 0x1b, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hslider_grabber_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc6, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x83, 0x83, 0x60, 0xaf, 0xb1, 0x65, 0xbb, 0xca, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x63, 0xb7, 0xc8, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x61, 0xb3, 0xbc, 0x60, 0xb1, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x63, 0xb4, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x69, 0x69, 0x5e, 0xb1, 0xcd, 0x5e, 0xb0, 0xcd, 0x36, 0x63, 0x63, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x60, 0xb2, 0xbd, 0x62, 0xb3, 0xbf, 0x3, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x9b, 0x9a, 0x52, 0x96, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x62, 0xb4, 0xbd, 0x63, 0xb7, 0xbf, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x51, 0x93, 0x92, 0x56, 0x9d, 0x9c, 0x0, 0x0, 0x0, 0x54, 0xa2, 0xc8, 0x4c, 0x94, 0xc2, 0x48, 0x8e, 0xc0, 0x47, 0x8c, 0xbf, 0x4b, 0x93, 0xc2, 0x4b, 0x92, 0xc2, 0x4f, 0x98, 0xc4, 0x4d, 0x96, 0xc3, 0x55, 0xa3, 0xc8, 0x53, 0x9f, 0xc7, 0x49, 0x8f, 0xc0, 0x4e, 0x97, 0xc4, 0x5a, 0xab, 0xcb, 0x5a, 0xac, 0xcc, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0xff, 0xff, 0xff, 0x6b, 0x1e, 0xb5, 0x61, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0xd, 0x1c, 0x27, 0x16, 0x6e, 0xc1, 0xef, 0xe8, 0x28, 0xf0, 0xf0, 0x22, 0xdb, 0xde, 0x24, 0x17, 0xaf, 0xc5, 0x1a, 0xa, 0x65, 0xfc, 0xfe, 0x64, 0xc, 0x31, 0xe0, 0xe0, 0x28, 0x2, 0x1, 0x14, 0x9c, 0x95, 0x13, 0x5, 0x2c, 0xdb, 0xdc, 0xb, 0x4f, 0xf4, 0xf7, 0x55, 0x73, 0x7d, 0x4, 0x28, 0xf1, 0xfd, 0xa1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x41, 0x89, 0xde, 0x6c, 0x4e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x9e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0xcf, 0xd7, 0x12, 0x82, 0x30, 0x10, 0x5, 0x50, 0x48, 0x42, 0x12, 0xb0, 0x77, 0x8d, 0xd, 0xb, 0x28, 0x56, 0x12, 0x62, 0xd, 0x96, 0xff, 0xff, 0x2a, 0x61, 0xc, 0xe0, 0x83, 0xfb, 0xb4, 0xf7, 0xcc, 0xec, 0xcc, 0x5d, 0xc3, 0xf8, 0x37, 0x26, 0x80, 0x8, 0x41, 0x60, 0xe6, 0xd9, 0xc2, 0x84, 0x52, 0x82, 0xad, 0x4c, 0x0, 0xb6, 0xb9, 0x10, 0xdc, 0xc6, 0x40, 0x3, 0x24, 0x3c, 0x92, 0x32, 0xe2, 0x4, 0x6a, 0x40, 0x54, 0xc8, 0x64, 0x4, 0x45, 0x1a, 0x9c, 0xd2, 0x29, 0x85, 0x73, 0xd9, 0xd1, 0x50, 0xa9, 0x5e, 0x52, 0xb8, 0xd6, 0xea, 0x1a, 0x1a, 0xcd, 0x5b, 0xa, 0xf7, 0x56, 0x5b, 0x43, 0xa7, 0xdb, 0x53, 0x52, 0xaa, 0xfe, 0x80, 0x65, 0x3d, 0x86, 0xa3, 0x58, 0xca, 0x78, 0x3c, 0x99, 0x6a, 0x70, 0x67, 0xf3, 0x87, 0x52, 0xcf, 0xc5, 0x32, 0xaf, 0xee, 0xf9, 0xab, 0xd7, 0x7b, 0xed, 0x7b, 0xc5, 0x33, 0xc1, 0x66, 0xbb, 0xdb, 0xb3, 0x22, 0x27, 0x47, 0x87, 0xa3, 0xe5, 0xfe, 0xfe, 0x1b, 0x6, 0x2c, 0xfc, 0x6e, 0x1f, 0x93, 0x2a, 0x10, 0x62, 0x3, 0x21, 0x32, 0x75, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x83, 0x83, 0x60, 0xaf, 0xb1, 0x65, 0xbb, 0xca, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x63, 0xb7, 0xc8, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x61, 0xb3, 0xbc, 0x60, 0xb1, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x63, 0xb4, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x69, 0x69, 0x5e, 0xb1, 0xcd, 0x5e, 0xb0, 0xcd, 0x36, 0x63, 0x63, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x60, 0xb2, 0xbd, 0x62, 0xb3, 0xbf, 0x3, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x9b, 0x9a, 0x52, 0x96, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x62, 0xb4, 0xbd, 0x63, 0xb7, 0xbf, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x51, 0x93, 0x92, 0x56, 0x9d, 0x9c, 0x0, 0x0, 0x0, 0x54, 0xa2, 0xc8, 0x4c, 0x94, 0xc2, 0x48, 0x8e, 0xc0, 0x47, 0x8c, 0xbf, 0x4b, 0x93, 0xc2, 0x4b, 0x92, 0xc2, 0x4f, 0x98, 0xc4, 0x4d, 0x96, 0xc3, 0x55, 0xa3, 0xc8, 0x53, 0x9f, 0xc7, 0x49, 0x8f, 0xc0, 0x4e, 0x97, 0xc4, 0x5a, 0xab, 0xcb, 0x5a, 0xac, 0xcc, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0xd4, 0xd, 0x1d, 0x1c, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0xd, 0x1c, 0x27, 0x16, 0x6e, 0xc1, 0xef, 0xe8, 0x28, 0xf0, 0xf0, 0x22, 0xdb, 0xde, 0x24, 0x17, 0xaf, 0xc5, 0x1a, 0xa, 0x65, 0xfc, 0xfe, 0x64, 0xc, 0x31, 0xe0, 0xe0, 0x28, 0x2, 0x1, 0x14, 0x9c, 0x95, 0x13, 0x5, 0x2c, 0xdb, 0xdc, 0xb, 0x4f, 0xf4, 0xf7, 0x55, 0x73, 0x7d, 0x4, 0x28, 0xf1, 0xfd, 0xa1, 0x0, 0x0, 0x0, 0x7d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xcc, 0x81, 0x6, 0xc3, 0x40, 0x10, 0x84, 0xe1, 0xdd, 0x9d, 0xd9, 0x3d, 0x40, 0x1f, 0xa1, 0x0, 0xd1, 0xbe, 0xff, 0xbb, 0x94, 0x10, 0x29, 0x40, 0x1a, 0x40, 0x9, 0xa, 0xbd, 0x34, 0x7b, 0x39, 0xfa, 0x63, 0xf0, 0x61, 0x4c, 0xfe, 0xfa, 0x81, 0x1a, 0x48, 0x98, 0x36, 0x50, 0x66, 0xda, 0x40, 0x71, 0xab, 0x41, 0x3b, 0xc, 0x56, 0x1b, 0x3a, 0xd4, 0x8e, 0x4d, 0x8, 0x40, 0x6a, 0x64, 0x24, 0x0, 0xb6, 0x83, 0xa1, 0x1, 0x79, 0x0, 0x79, 0xc2, 0x54, 0x44, 0xca, 0x14, 0x91, 0xb0, 0xba, 0xef, 0xa7, 0xee, 0x9e, 0x70, 0x8d, 0xd0, 0x52, 0x2c, 0xe2, 0x99, 0x30, 0x93, 0xb, 0x7d, 0x81, 0x4a, 0x82, 0x8c, 0xc0, 0xba, 0xfa, 0x7b, 0x3c, 0x41, 0xb6, 0xd, 0x78, 0x84, 0x74, 0x98, 0x2f, 0x9f, 0xd7, 0x7d, 0x96, 0xbd, 0x2f, 0xa5, 0x6b, 0x13, 0xc4, 0x35, 0x90, 0x18, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hslider_tick_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xc3, 0x98, 0xc3, 0xc0, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x1e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x38, 0x55, 0x5f, 0x8c, 0xac, 0xb8, 0x81, 0xa2, 0xad, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x8d, 0x8d, 0x8d, 0x82, 0x82, 0x82, 0x4e, 0x4e, 0x4e, 0xff, 0xff, 0xff, 0xc1, 0xc9, 0xb1, 0x80, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x31, 0x79, 0x79, 0x1c, 0x7e, 0xed, 0x4b, 0xf4, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x9, 0xf1, 0xd9, 0xa5, 0xec, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x21, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x9, 0x60, 0x60, 0xb, 0x60, 0x60, 0xf, 0x60, 0x60, 0x6d, 0x60, 0x60, 0x14, 0x60, 0xc0, 0x4, 0x4c, 0x2, 0xc, 0xcc, 0x2, 0xc, 0x30, 0x65, 0x0, 0x46, 0x9d, 0x2, 0xbe, 0x9f, 0x3a, 0x6c, 0xab, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xc3, 0x98, 0xc3, 0xc0, 0x0, 0x0, 0x0, 0x1b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x38, 0x55, 0x5f, 0x8c, 0xac, 0xb8, 0x81, 0xa2, 0xad, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x8d, 0x8d, 0x8d, 0x82, 0x82, 0x82, 0x4e, 0x4e, 0x4e, 0xc9, 0xf6, 0x7, 0x31, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x31, 0x79, 0x79, 0x1c, 0x7e, 0xed, 0x4b, 0xf4, 0x0, 0x0, 0x0, 0x20, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x9, 0x60, 0x60, 0xb, 0x60, 0x60, 0xf, 0x60, 0x60, 0x6d, 0x60, 0x60, 0x14, 0x60, 0xc0, 0x4, 0x4c, 0x2, 0xc, 0xcc, 0x2, 0x70, 0x65, 0x0, 0x46, 0x9d, 0x2, 0xbe, 0xb7, 0xdf, 0x14, 0x38, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hsplit_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hsplitter_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x40, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, 0x6f, 0x69, 0x56, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x27, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x80, 0x2, 0x66, 0x86, 0x5, 0xa2, 0xe7, 0x18, 0x16, 0x88, 0x9e, 0x63, 0x66, 0x10, 0xbd, 0xf6, 0x98, 0x41, 0xf4, 0xda, 0x63, 0x6, 0xc, 0x30, 0xaa, 0x66, 0x54, 0xd, 0x9a, 0x1a, 0x0, 0x5c, 0x29, 0x6a, 0x81, 0x90, 0x8f, 0x52, 0x12, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x40, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, 0x6f, 0x69, 0x56, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x1a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x80, 0x5, 0xa9, 0x10, 0xcc, 0x90, 0x6a, 0xd, 0xc6, 0x70, 0x80, 0x4b, 0xcd, 0xa8, 0x9a, 0x51, 0x35, 0x0, 0x78, 0xd5, 0x34, 0xa1, 0x54, 0x8c, 0xd5, 0x84, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_add_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0xa0, 0x25, 0x78, 0xf0, 0xe0, 0xc1, 0xff, 0x7, 0xf, 0x1e, 0xfc, 0xc7, 0xa7, 0x86, 0x89, 0x52, 0x4b, 0x46, 0xd, 0x60, 0x60, 0x60, 0x64, 0x60, 0x80, 0x84, 0x36, 0x39, 0x9a, 0x15, 0x14, 0x14, 0x18, 0x29, 0x76, 0x1, 0x5e, 0x30, 0x9a, 0xe, 0xe8, 0x64, 0x0, 0xc5, 0x0, 0x0, 0xc7, 0x6e, 0x12, 0x94, 0xf9, 0x26, 0x2e, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x3c, 0xf8, 0xff, 0xe0, 0xff, 0xd0, 0x52, 0x80, 0x10, 0xc4, 0xd, 0x9, 0x2a, 0x18, 0x26, 0xe1, 0x40, 0x18, 0x0, 0x0, 0x5b, 0x26, 0x61, 0x4d, 0xc9, 0xc1, 0x48, 0x81, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_close_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x67, 0xdb, 0x58, 0xd0, 0xd3, 0xf0, 0xa3, 0x7c, 0x36, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x85, 0x14, 0x81, 0xf, 0x2c, 0x28, 0xe0, 0xda, 0xd5, 0x8c, 0x4e, 0x77, 0xb, 0xfc, 0xd5, 0x98, 0xd9, 0x20, 0x29, 0x7a, 0xb9, 0xa4, 0x68, 0x66, 0x83, 0xb, 0x93, 0xcc, 0x24, 0xa7, 0x9a, 0x44, 0x52, 0x24, 0x39, 0x91, 0xcc, 0x55, 0x89, 0xa4, 0xde, 0xcc, 0xce, 0x24, 0xb, 0xc9, 0x39, 0x84, 0xb0, 0xf7, 0xb2, 0xae, 0xeb, 0x76, 0xde, 0x8a, 0x4f, 0x92, 0x66, 0xd8, 0x91, 0x5c, 0x49, 0x5e, 0x9a, 0xe1, 0xb5, 0x64, 0x5, 0x16, 0x92, 0x8b, 0x7, 0x6f, 0x9b, 0x8c, 0x0, 0x4a, 0x29, 0x9b, 0x26, 0x81, 0xa4, 0x3e, 0xa5, 0x34, 0x2, 0x38, 0x2, 0x58, 0x0, 0xcc, 0x0, 0xe, 0x39, 0xe7, 0xd3, 0xfa, 0xb0, 0xee, 0xea, 0x8f, 0x7, 0x7b, 0xf5, 0x9d, 0xb7, 0xb0, 0x97, 0x55, 0x25, 0x5f, 0x17, 0xe9, 0x2e, 0xf9, 0xb8, 0xca, 0x3f, 0x9b, 0x1b, 0x1a, 0xe3, 0x40, 0x47, 0xa0, 0xda, 0xda, 0x61, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_color_pick_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x1, 0x55, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xb5, 0x92, 0xb1, 0x4a, 0x3, 0x41, 0x14, 0x45, 0xef, 0xdb, 0x6c, 0xac, 0xf2, 0x1, 0xda, 0xcd, 0x40, 0x4, 0x25, 0x11, 0x4, 0x8b, 0x80, 0x8d, 0x20, 0x88, 0x5d, 0x20, 0x88, 0x90, 0x22, 0x9d, 0x9d, 0xa0, 0x85, 0x58, 0xeb, 0x7, 0x88, 0xe0, 0x7, 0x58, 0x8b, 0x36, 0x5a, 0x88, 0xa0, 0xa5, 0x85, 0xa5, 0x60, 0x61, 0xb0, 0x70, 0xb2, 0xef, 0x8d, 0x44, 0x41, 0x21, 0x1f, 0x20, 0x6c, 0xf2, 0x2c, 0xcc, 0xc2, 0x12, 0x92, 0x8d, 0x45, 0xbc, 0xe5, 0xdc, 0xb9, 0x67, 0xee, 0xbc, 0x19, 0xe0, 0xbf, 0xe5, 0xbd, 0x2f, 0x35, 0x9b, 0xcd, 0x29, 0x0, 0x10, 0x91, 0x9a, 0x88, 0x7c, 0x88, 0xc8, 0xa7, 0x88, 0xd4, 0x0, 0x80, 0xb2, 0xc2, 0xcc, 0x5c, 0x21, 0xa2, 0x5b, 0x22, 0xba, 0xef, 0x76, 0xbb, 0x97, 0x44, 0x74, 0x4a, 0x44, 0x61, 0xdf, 0xfe, 0x32, 0xc6, 0x4c, 0x87, 0x59, 0x0, 0x0, 0xdf, 0x0, 0x62, 0x55, 0xad, 0x6, 0x41, 0x50, 0x1d, 0xf0, 0x62, 0x0, 0x8, 0xb2, 0xd2, 0xd6, 0xda, 0x27, 0x0, 0x27, 0x83, 0xeb, 0xaa, 0x1a, 0x3, 0xd8, 0x19, 0xb, 0x60, 0xe6, 0x3a, 0x80, 0x6d, 0x0, 0xd, 0x0, 0x9d, 0x14, 0x60, 0xcb, 0x18, 0x73, 0x95, 0x9, 0x60, 0xe6, 0x3a, 0x11, 0x1d, 0xc7, 0x71, 0xbc, 0x6e, 0x8c, 0x39, 0x53, 0xd5, 0xdd, 0xc4, 0xcb, 0xe5, 0x72, 0x1b, 0xc9, 0x60, 0x87, 0x2, 0xd2, 0xe1, 0x62, 0xb1, 0xf8, 0xec, 0xbd, 0x2f, 0x11, 0xd1, 0x51, 0xaf, 0xd7, 0x3b, 0x0, 0xd0, 0x51, 0xd5, 0x95, 0x42, 0xa1, 0x30, 0x3b, 0xf2, 0x64, 0x11, 0x79, 0x77, 0xce, 0x95, 0x81, 0xdf, 0x67, 0x14, 0x91, 0x76, 0xff, 0x3a, 0x60, 0xe6, 0x45, 0x66, 0xae, 0xc, 0xd, 0x47, 0x51, 0xb4, 0x29, 0x22, 0xed, 0x56, 0xab, 0xb5, 0xd0, 0xdf, 0x3c, 0xe7, 0xbd, 0x7f, 0x8b, 0xa2, 0xa8, 0x31, 0x7a, 0x52, 0x93, 0x8, 0x8b, 0xc8, 0x72, 0xba, 0xb6, 0x73, 0xae, 0x9c, 0xae, 0x9d, 0xa5, 0x0, 0x0, 0x88, 0x68, 0xd, 0xc0, 0x8b, 0xaa, 0xbe, 0x3a, 0xe7, 0xca, 0x61, 0x18, 0xde, 0xa9, 0xea, 0xbe, 0xb5, 0xf6, 0x7c, 0x1c, 0x20, 0xf9, 0x89, 0x4b, 0x0, 0x56, 0xf3, 0xf9, 0xfc, 0xd, 0x80, 0x79, 0x55, 0xdd, 0xb3, 0xd6, 0x5e, 0x8c, 0xad, 0x9e, 0x0, 0x54, 0x75, 0x86, 0x88, 0xae, 0x1, 0x3c, 0x2, 0x38, 0x34, 0xc6, 0x3c, 0xfc, 0x25, 0x3c, 0x11, 0xfd, 0x0, 0x28, 0x54, 0xbb, 0xfe, 0xad, 0x99, 0xe5, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xaa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x9d, 0x8e, 0x35, 0x82, 0x2, 0x41, 0x10, 0x45, 0x3b, 0xda, 0x3d, 0xca, 0xba, 0x44, 0x2b, 0x70, 0x9, 0xdc, 0xe1, 0x20, 0xe8, 0x91, 0x90, 0x78, 0x6e, 0x40, 0x4c, 0x82, 0x74, 0xff, 0xc2, 0x9d, 0x18, 0xa7, 0x6, 0x77, 0x7b, 0x23, 0x2d, 0xaf, 0x4c, 0xdc, 0xc, 0xbd, 0x65, 0x1e, 0x84, 0x80, 0x19, 0x55, 0x34, 0x60, 0x3e, 0xd0, 0xea, 0x17, 0x3d, 0x4a, 0xc8, 0x80, 0x1a, 0x60, 0xc2, 0x4f, 0xfd, 0x30, 0xe0, 0x1b, 0x2d, 0x16, 0xab, 0xa7, 0x2c, 0xe, 0x41, 0x68, 0xa5, 0xb9, 0xca, 0x91, 0x16, 0x2e, 0x54, 0xe0, 0x59, 0x54, 0x91, 0xfe, 0xa3, 0x3a, 0xff, 0xce, 0xab, 0x5b, 0xf, 0xa0, 0x4, 0x8f, 0x7b, 0x4c, 0xd3, 0x1b, 0xca, 0x32, 0xcc, 0x55, 0x7a, 0xf4, 0x76, 0x42, 0x2b, 0x97, 0x3e, 0xae, 0xfa, 0xdd, 0xd2, 0xd2, 0x8e, 0x72, 0xe1, 0x83, 0xaf, 0x9f, 0xa9, 0x28, 0x7d, 0x5b, 0xe2, 0x2a, 0xd, 0xc3, 0xa2, 0x78, 0xfe, 0x7d, 0x51, 0xfc, 0x0, 0x8a, 0x41, 0xcb, 0x3d, 0xb2, 0xae, 0x1c, 0xd3, 0xc, 0xa5, 0x30, 0x81, 0xc6, 0xda, 0x29, 0x8e, 0x83, 0x34, 0x25, 0x29, 0x4a, 0x46, 0x71, 0x1f, 0x33, 0xbe, 0x51, 0x89, 0xaf, 0x78, 0xe3, 0x97, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_folder_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x8f, 0xc1, 0xd, 0x80, 0x30, 0x8, 0x45, 0x9f, 0x9d, 0x84, 0x39, 0x4c, 0x3b, 0xbd, 0x75, 0x8f, 0x32, 0x9, 0x5e, 0xec, 0xa5, 0x9, 0xa4, 0xc6, 0x26, 0x5e, 0x7c, 0x17, 0xe, 0xc0, 0xe3, 0x3, 0x5f, 0xb3, 0x1, 0xb4, 0xd6, 0x4e, 0x60, 0x77, 0x66, 0xaa, 0x88, 0x14, 0x4f, 0x90, 0xee, 0xea, 0x2d, 0x3, 0xe4, 0x28, 0x41, 0x8a, 0x9a, 0x1d, 0x55, 0x75, 0x25, 0xfd, 0x5, 0x9b, 0x11, 0xd, 0x54, 0x11, 0x29, 0x53, 0x9, 0x1c, 0x32, 0x4c, 0xbe, 0x10, 0xf1, 0xb, 0x16, 0xa, 0xea, 0xd3, 0x45, 0x33, 0x3b, 0xde, 0x1e, 0x5f, 0xc3, 0x5, 0x1f, 0xc5, 0x12, 0x2c, 0xc5, 0x88, 0xe1, 0xb4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x6, 0x78, 0x70, 0xf4, 0xc1, 0x7f, 0x24, 0x78, 0x18, 0x53, 0xc1, 0x7f, 0x54, 0x48, 0x50, 0xc1, 0x43, 0x1b, 0xbc, 0xa, 0x50, 0xad, 0x23, 0xa4, 0xe0, 0xff, 0x70, 0x52, 0x70, 0x18, 0x97, 0xf4, 0xfd, 0x43, 0xd4, 0x88, 0x4a, 0x0, 0x5a, 0xcb, 0x18, 0xab, 0x5e, 0xd9, 0x1a, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_parent_folder_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0xc6, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xdd, 0x90, 0xbd, 0x6a, 0x2, 0x51, 0x10, 0x46, 0xcf, 0x8c, 0xbb, 0xaf, 0x10, 0xdb, 0xcb, 0x2e, 0x4b, 0x40, 0xf2, 0x14, 0x51, 0x8b, 0x3c, 0x70, 0x44, 0x48, 0x48, 0x15, 0x4c, 0x61, 0x67, 0xd2, 0x4, 0x96, 0xb, 0x5b, 0x89, 0x58, 0x59, 0xee, 0x8f, 0x3b, 0x36, 0xbb, 0x8d, 0x78, 0xa3, 0x92, 0x4a, 0x4f, 0xf9, 0xcd, 0xcc, 0x99, 0x61, 0xe0, 0xe6, 0x91, 0x50, 0xc1, 0x7b, 0x3f, 0x54, 0xd5, 0x39, 0x60, 0x6d, 0xdb, 0xbe, 0x24, 0x49, 0xb2, 0xb9, 0x58, 0x90, 0xe7, 0xf9, 0x43, 0x1c, 0xc7, 0xef, 0x66, 0xf6, 0xd4, 0x45, 0xbf, 0xc0, 0xb3, 0x73, 0x6e, 0x7d, 0x56, 0x70, 0x62, 0xb8, 0xe7, 0xa4, 0x44, 0x8f, 0xcf, 0x8e, 0xa2, 0xe8, 0xa3, 0x1b, 0xfe, 0xee, 0x62, 0x13, 0x91, 0x1f, 0xe0, 0x11, 0x78, 0xf3, 0xde, 0xf, 0x83, 0x2, 0x55, 0x9d, 0x1, 0x23, 0x60, 0xd5, 0x34, 0xcd, 0xb4, 0xcf, 0xab, 0xaa, 0x1a, 0x77, 0xc2, 0x91, 0xaa, 0xbe, 0x6, 0x5, 0xc0, 0xe, 0xf8, 0x2a, 0xcb, 0x72, 0x92, 0xa6, 0xe9, 0xb6, 0xf, 0xb3, 0x2c, 0xdb, 0xd6, 0x75, 0x3d, 0x11, 0x91, 0x25, 0x50, 0xfe, 0xf9, 0x83, 0x1e, 0x33, 0x93, 0xa2, 0x28, 0xf6, 0x80, 0x39, 0xe7, 0x6, 0xa1, 0xbe, 0xe3, 0xb, 0xae, 0x26, 0x28, 0x10, 0x11, 0x3, 0x16, 0x22, 0xf2, 0xf9, 0xdf, 0x25, 0xf7, 0xce, 0x1, 0x9e, 0x13, 0x48, 0xe9, 0x87, 0xc5, 0x3a, 0xd2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x68, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x33, 0xb8, 0x27, 0xfe, 0xe0, 0xfc, 0x83, 0x73, 0xf7, 0xc4, 0x71, 0x48, 0xdf, 0x11, 0x7b, 0x78, 0xe9, 0xc1, 0x3f, 0x20, 0xbc, 0xfe, 0x40, 0x12, 0x8f, 0x34, 0x4c, 0x9, 0xa6, 0xe1, 0x57, 0x80, 0x12, 0x17, 0x81, 0xf8, 0x2f, 0x58, 0xe1, 0x15, 0x34, 0x8b, 0x1e, 0x9c, 0x5, 0xa, 0x5e, 0xb8, 0x23, 0x6, 0x52, 0x70, 0x5b, 0x14, 0xac, 0xf0, 0xc, 0xaa, 0x82, 0x7d, 0xf, 0x8e, 0xde, 0x14, 0xf9, 0xcf, 0x8, 0x52, 0xc0, 0xc0, 0x70, 0x5b, 0xf4, 0xe1, 0xc9, 0x7, 0x47, 0xb1, 0xb8, 0x3, 0xaa, 0x0, 0xa, 0x48, 0x52, 0x80, 0xb0, 0xea, 0xc8, 0xc3, 0x83, 0xc, 0x83, 0xe, 0x0, 0x0, 0xb8, 0x27, 0x55, 0x4c, 0xbe, 0xc0, 0xd2, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_play_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xa2, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0xf2, 0x80, 0x11, 0x99, 0xf3, 0xe0, 0xc1, 0x83, 0xc3, 0xc, 0xc, 0xc, 0xc2, 0xc, 0xc, 0xc, 0xa5, 0xa, 0xa, 0xa, 0x5b, 0xc9, 0x31, 0xe0, 0x3f, 0x5c, 0x82, 0x91, 0x71, 0x27, 0x3, 0x3, 0x43, 0x91, 0xbc, 0xbc, 0xfc, 0x35, 0x7c, 0x6, 0x30, 0xe1, 0x92, 0xf8, 0xff, 0xff, 0xbf, 0xfb, 0xff, 0xff, 0xff, 0x2f, 0x3e, 0x78, 0xf0, 0x60, 0xca, 0x93, 0x27, 0x4f, 0x84, 0x49, 0x76, 0x1, 0x1a, 0xf8, 0xc0, 0xc8, 0xc8, 0xd8, 0xf1, 0xeb, 0xd7, 0xaf, 0x9, 0xaa, 0xaa, 0xaa, 0x3f, 0x89, 0x72, 0x1, 0x1a, 0x10, 0xf8, 0xff, 0xff, 0x7f, 0x7, 0x2b, 0x2b, 0xeb, 0x1e, 0x74, 0x9, 0x62, 0xd, 0xc0, 0x9, 0x88, 0x35, 0xe0, 0x3d, 0x23, 0x23, 0x63, 0xc5, 0xef, 0xdf, 0xbf, 0x5d, 0xd0, 0x25, 0x58, 0x8, 0x68, 0xfc, 0xc3, 0xc0, 0xc0, 0x30, 0x93, 0x85, 0x85, 0xa5, 0x5e, 0x46, 0x46, 0xe6, 0x2d, 0x36, 0x5, 0x38, 0xd, 0x20, 0x36, 0x1a, 0xd1, 0xd, 0x38, 0xc2, 0x0, 0x4d, 0x48, 0xf2, 0xf2, 0xf2, 0x44, 0x25, 0xa4, 0x61, 0x0, 0x0, 0x1e, 0x57, 0x33, 0x3c, 0xcc, 0xe7, 0x34, 0x69, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x41, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x1b, 0x78, 0x70, 0xf8, 0xc1, 0xb5, 0x7, 0xde, 0xf8, 0x14, 0xfc, 0x7, 0xc1, 0x87, 0x3b, 0x1e, 0x6a, 0xe1, 0x54, 0x0, 0x85, 0xbf, 0x1f, 0x4c, 0x79, 0x22, 0x8c, 0x5d, 0x1, 0x2, 0xbe, 0x7f, 0x58, 0x7e, 0x9b, 0x1d, 0x43, 0x1, 0x1a, 0x3c, 0x4c, 0x91, 0x82, 0x77, 0x8, 0x2b, 0x8, 0x3b, 0x12, 0xd3, 0x9b, 0x84, 0x3, 0x8a, 0xfe, 0x0, 0x0, 0xa4, 0x15, 0x70, 0xca, 0x48, 0x40, 0x6f, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_reload_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x1, 0x59, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0x4b, 0x3, 0x31, 0x18, 0x86, 0x9f, 0x5c, 0xe, 0xec, 0x20, 0x76, 0x70, 0x39, 0xd0, 0xe3, 0xba, 0x74, 0x51, 0x41, 0xdd, 0xfc, 0x7, 0xba, 0xb8, 0x8, 0x52, 0xec, 0x2e, 0x4e, 0x3a, 0x88, 0x3f, 0xa3, 0xa3, 0x53, 0x7, 0x47, 0x67, 0x41, 0x17, 0xdd, 0x9c, 0x5c, 0x3b, 0xd8, 0x82, 0x64, 0x68, 0xca, 0xd5, 0x55, 0x11, 0x3c, 0x1a, 0x87, 0x24, 0x2e, 0xd7, 0x72, 0x9e, 0x9e, 0xab, 0xbe, 0xd3, 0xc7, 0x1b, 0x9e, 0x37, 0xf9, 0xbe, 0x7c, 0xf0, 0xd7, 0x12, 0x3f, 0x99, 0x4a, 0xa9, 0xb9, 0x30, 0xc, 0x8f, 0x84, 0x10, 0x7, 0xc0, 0x5a, 0x6e, 0x3f, 0x3a, 0xe7, 0x2e, 0xad, 0xb5, 0xdd, 0x66, 0xb3, 0xf9, 0x51, 0x19, 0x90, 0xa6, 0xe9, 0x92, 0xb5, 0xf6, 0x6, 0x58, 0xaf, 0xb8, 0xb4, 0x27, 0xa5, 0xdc, 0x8d, 0xe3, 0xf8, 0x19, 0x20, 0x28, 0xdf, 0x5c, 0x80, 0x53, 0x60, 0xdf, 0x18, 0x53, 0x37, 0xc6, 0xd4, 0xbd, 0xf7, 0x7b, 0xc0, 0x13, 0xb0, 0x61, 0xad, 0xbd, 0x56, 0x4a, 0xcd, 0x1, 0x84, 0xc5, 0x80, 0x30, 0xc, 0x8f, 0xa6, 0xb0, 0x94, 0x72, 0x33, 0x8e, 0xe3, 0x97, 0xc2, 0xf1, 0xd5, 0x68, 0x34, 0xba, 0xf7, 0xde, 0xf7, 0x80, 0xd, 0x29, 0xe5, 0x21, 0x70, 0xfe, 0xe5, 0x5, 0x42, 0x88, 0x76, 0x5e, 0x9e, 0x96, 0x60, 0x0, 0x92, 0x24, 0x79, 0x75, 0xce, 0x9d, 0x1, 0x4, 0x41, 0xd0, 0xfe, 0xd6, 0x2, 0xb0, 0x2, 0x60, 0x8c, 0xb9, 0xab, 0xe8, 0x1f, 0x6b, 0xed, 0x6d, 0x5e, 0xae, 0xce, 0x2, 0xb4, 0xd6, 0x17, 0x5a, 0x6b, 0x7, 0xcc, 0x3, 0xd4, 0x6a, 0xb5, 0x37, 0xad, 0xf5, 0xc5, 0x4f, 0x1, 0x41, 0x10, 0x7c, 0x19, 0x7c, 0x90, 0x3, 0xc7, 0xc0, 0xa0, 0xe0, 0xf, 0x72, 0xef, 0x9b, 0x84, 0x10, 0xdb, 0x79, 0xd9, 0x9f, 0x5, 0x44, 0x51, 0x94, 0x9, 0x21, 0x5a, 0x40, 0x6, 0x64, 0x42, 0x88, 0x56, 0x14, 0x45, 0x59, 0x19, 0x1e, 0x8f, 0xc7, 0x8b, 0x52, 0xca, 0xe, 0x80, 0x73, 0xee, 0x12, 0xa, 0xbf, 0x90, 0x24, 0x49, 0x7f, 0x38, 0x1c, 0x1e, 0x3, 0x34, 0x1a, 0x8d, 0x7e, 0x11, 0x54, 0x4a, 0x2d, 0x48, 0x29, 0x77, 0xac, 0xb5, 0x1d, 0xef, 0xfd, 0x32, 0xd0, 0x9b, 0x4c, 0x26, 0x5d, 0xa8, 0xd8, 0xc4, 0xb2, 0xf2, 0xf9, 0x4c, 0x55, 0xbd, 0x48, 0xbf, 0xe8, 0x1d, 0x78, 0x70, 0xce, 0x9d, 0x64, 0x59, 0xb6, 0x35, 0x85, 0xff, 0x87, 0x3e, 0x1, 0x53, 0x7, 0x87, 0x11, 0xd3, 0x3a, 0x9b, 0x9e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xb1, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x50, 0x35, 0xba, 0xc2, 0x40, 0x10, 0x7e, 0xcd, 0x33, 0x5c, 0xca, 0x1c, 0x21, 0x87, 0xc1, 0xa9, 0xd3, 0x23, 0x47, 0xca, 0x69, 0xb0, 0x6, 0x77, 0xdb, 0xfd, 0x17, 0x2f, 0x91, 0x3e, 0xee, 0xd2, 0xc1, 0x4e, 0xb5, 0xdf, 0xcc, 0xaf, 0x5f, 0x9f, 0x7c, 0xdb, 0x5f, 0xda, 0x44, 0x17, 0x2f, 0x75, 0xba, 0xa4, 0xb1, 0xfd, 0xf5, 0xad, 0x8f, 0x1c, 0x86, 0x90, 0x5c, 0x33, 0x38, 0x72, 0x1e, 0xb4, 0xbe, 0x66, 0x28, 0xad, 0xe2, 0xab, 0x38, 0xcd, 0x63, 0xa9, 0x9d, 0xb8, 0x58, 0x68, 0x53, 0x5b, 0x1f, 0x33, 0xd6, 0x9f, 0xa5, 0xc1, 0x20, 0x91, 0xba, 0x7d, 0x80, 0x1e, 0x24, 0x94, 0xdc, 0x92, 0xa4, 0x2, 0x9, 0x1d, 0xe7, 0xe0, 0x9, 0x69, 0x15, 0xf7, 0x58, 0x4e, 0x40, 0xc2, 0xc3, 0x58, 0x8a, 0xb6, 0x31, 0xd1, 0x39, 0xd8, 0x27, 0xed, 0x83, 0x5b, 0x14, 0x33, 0x7d, 0x3d, 0xbb, 0x45, 0x5d, 0x12, 0x55, 0x97, 0x4, 0xe3, 0xb5, 0xf4, 0x8c, 0x77, 0xd6, 0xa7, 0x2c, 0x3b, 0x78, 0x4c, 0x52, 0x81, 0xa, 0x8e, 0x3a, 0xa9, 0x6a, 0x6b, 0xc, 0xe6, 0x3f, 0xa1, 0x8d, 0x86, 0x16, 0xe5, 0x39, 0x78, 0xa2, 0x4d, 0xea, 0xe, 0xfa, 0xdd, 0xa7, 0x0, 0x90, 0x4f, 0x8b, 0xd0, 0xe1, 0x9e, 0x1b, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_snap_grid_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0xc2, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xad, 0x90, 0xbd, 0xa, 0xc2, 0x30, 0x14, 0x85, 0xbf, 0x5b, 0x5c, 0x23, 0xe8, 0x6c, 0x9f, 0xc1, 0xb7, 0xd0, 0x47, 0xd1, 0x47, 0x70, 0x48, 0xa1, 0x43, 0x57, 0xe9, 0xd3, 0x88, 0x93, 0xef, 0xe0, 0xea, 0x5c, 0x9d, 0x1d, 0xb2, 0x96, 0xc6, 0xa1, 0x9, 0xd4, 0xd8, 0xd8, 0x4a, 0xfd, 0x20, 0x10, 0xee, 0xcf, 0xe1, 0xdc, 0x3, 0x1d, 0x8c, 0x31, 0xd6, 0x18, 0x63, 0x9, 0x88, 0xd5, 0x1, 0x92, 0xbe, 0xe2, 0x2f, 0x4c, 0x16, 0x90, 0x98, 0xb5, 0x21, 0x94, 0x52, 0xf2, 0x17, 0x7, 0x6f, 0x7c, 0xb, 0x2b, 0xc6, 0x64, 0x7, 0xb3, 0xa1, 0x1, 0x5b, 0x14, 0x29, 0x50, 0x2, 0x1b, 0x0, 0x44, 0x2e, 0x34, 0xcd, 0x41, 0xb2, 0xec, 0x6, 0x20, 0xdd, 0x61, 0x6f, 0xdf, 0x7, 0xe4, 0x96, 0xaf, 0xc0, 0x32, 0xd0, 0x7d, 0x2, 0x6b, 0xd1, 0xba, 0x4a, 0xfc, 0xdd, 0x91, 0xdb, 0x4b, 0xb7, 0x7c, 0x2, 0x56, 0xd4, 0x75, 0xa, 0x9c, 0x81, 0x5, 0x70, 0x84, 0xe1, 0xc, 0x5a, 0xdb, 0x75, 0xbd, 0x17, 0xad, 0x1f, 0x92, 0xe7, 0x77, 0x60, 0xe7, 0x7a, 0x5b, 0x80, 0x44, 0x29, 0x25, 0xfe, 0xf5, 0x8, 0x28, 0x0, 0xb7, 0xd8, 0x46, 0xa0, 0x75, 0xe5, 0xbe, 0xf3, 0x31, 0xe, 0x7e, 0x23, 0xcc, 0xc2, 0x3a, 0xc2, 0xb9, 0x58, 0xfd, 0x83, 0xc9, 0x2, 0x63, 0x78, 0x1, 0x4a, 0x50, 0x70, 0x86, 0xcc, 0x86, 0x2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf3, 0xf3, 0xf3, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x85, 0x85, 0xff, 0x83, 0x83, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x80, 0x80, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0xff, 0xff, 0xa, 0xa5, 0x43, 0x1, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xff, 0x1d, 0xac, 0xf2, 0xaf, 0x27, 0xed, 0xff, 0xee, 0xb4, 0x1b, 0x1c, 0xb6, 0xaa, 0xf1, 0x50, 0xa6, 0xdd, 0x5f, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x0, 0x2, 0x40, 0x23, 0xd3, 0x60, 0x0, 0x40, 0xc, 0x3, 0xaf, 0x76, 0x93, 0xfd, 0x97, 0x7d, 0x9b, 0x55, 0x70, 0x12, 0x62, 0xaf, 0x68, 0x0, 0xc4, 0xe9, 0x3c, 0x1, 0x67, 0xf7, 0x17, 0x20, 0x95, 0xd6, 0xc6, 0xee, 0x80, 0x74, 0xde, 0x7b, 0x1f, 0x24, 0xb0, 0x64, 0x29, 0x1f, 0x53, 0x2e, 0xbe, 0x6e, 0x80, 0xf6, 0x19, 0x90, 0x9e, 0x36, 0x8b, 0xf7, 0xc0, 0x5c, 0xdf, 0x0, 0x66, 0x60, 0xae, 0xf3, 0xb9, 0x1, 0xfb, 0xe9, 0x1, 0xa6, 0x26, 0x1, 0xcd, 0x30, 0x66, 0x63, 0x6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_stop_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x2b, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x20, 0xc, 0x3e, 0x30, 0xe3, 0x93, 0x61, 0x64, 0x60, 0x60, 0x60, 0x78, 0xf8, 0x1f, 0xbb, 0x2, 0x79, 0x46, 0x6, 0x6, 0x26, 0x42, 0xe6, 0x8f, 0x2a, 0xa0, 0x96, 0x2, 0x6, 0x42, 0x91, 0x45, 0x10, 0x0, 0x0, 0x95, 0x31, 0x5, 0xe4, 0xe, 0x1, 0x8e, 0x3, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x2, 0x7c, 0x60, 0x26, 0x28, 0xf3, 0xf0, 0x3f, 0x76, 0x8, 0x94, 0xa2, 0x97, 0x82, 0x51, 0x5, 0x84, 0x23, 0x8b, 0x30, 0x0, 0x0, 0x66, 0x60, 0x11, 0xdc, 0x92, 0xb3, 0xb7, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_zoom_less_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x25, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0x5, 0xc3, 0x0, 0x30, 0x32, 0x30, 0x30, 0x30, 0x3c, 0x78, 0xf0, 0xe0, 0x3f, 0x39, 0x9a, 0x15, 0x14, 0x14, 0x18, 0x99, 0xa8, 0xeb, 0x9e, 0x51, 0x30, 0x44, 0x1, 0x0, 0xff, 0xa9, 0x4, 0x4, 0x4a, 0xae, 0x20, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x13, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x31, 0xe0, 0xc1, 0x7f, 0x3c, 0x90, 0xb0, 0x82, 0x11, 0x2, 0x0, 0xbf, 0x57, 0x36, 0x25, 0x52, 0x24, 0x7b, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_zoom_more_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0xa0, 0x25, 0x78, 0xf0, 0xe0, 0xc1, 0xff, 0x7, 0xf, 0x1e, 0xfc, 0xc7, 0xa7, 0x86, 0x89, 0x52, 0x4b, 0x46, 0xd, 0x60, 0x60, 0x60, 0x64, 0x60, 0x80, 0x84, 0x36, 0x39, 0x9a, 0x15, 0x14, 0x14, 0x18, 0x29, 0x76, 0x1, 0x5e, 0x30, 0x9a, 0xe, 0xe8, 0x64, 0x0, 0xc5, 0x0, 0x0, 0xc7, 0x6e, 0x12, 0x94, 0xf9, 0x26, 0x2e, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x3c, 0xf8, 0xf, 0x84, 0x43, 0x4a, 0x1, 0x42, 0x10, 0xf, 0x24, 0xa8, 0x60, 0x78, 0x84, 0x3, 0x61, 0x0, 0x0, 0xca, 0x3a, 0x6d, 0x8d, 0x50, 0x1e, 0x9a, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_zoom_reset_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xdd, 0x91, 0xbb, 0xd, 0x80, 0x30, 0x10, 0x43, 0x1f, 0x11, 0x23, 0x20, 0xea, 0x4c, 0xc5, 0x62, 0x48, 0xec, 0xc0, 0x56, 0x97, 0x26, 0x43, 0xa4, 0x31, 0x15, 0x12, 0x45, 0x72, 0x8a, 0x14, 0xa, 0x84, 0xab, 0xfb, 0x58, 0x3e, 0xeb, 0xc, 0x83, 0x98, 0xee, 0x22, 0xa5, 0xb4, 0x49, 0x3a, 0x1, 0x62, 0x8c, 0x53, 0x8d, 0x5c, 0xe3, 0x4, 0x80, 0x9c, 0xf3, 0x22, 0x69, 0xf7, 0x2e, 0xb5, 0x38, 0x1, 0xa0, 0x94, 0x72, 0x0, 0xab, 0x27, 0xd0, 0xc3, 0xc1, 0xcc, 0x64, 0x66, 0x6a, 0xf5, 0xb5, 0x59, 0x70, 0x15, 0x3b, 0x30, 0x7b, 0xcb, 0xd6, 0x33, 0x9f, 0x18, 0x76, 0xf0, 0x71, 0x81, 0x5a, 0xa, 0xaf, 0x3b, 0xf8, 0x41, 0xa, 0xc3, 0xb8, 0x0, 0x6c, 0x9c, 0x3f, 0xb8, 0x84, 0xfc, 0x5b, 0x85, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0xa, 0x3c, 0xc, 0x7b, 0xf0, 0xff, 0xc1, 0x7f, 0x9c, 0x22, 0xcf, 0x44, 0x1e, 0xbc, 0x84, 0x72, 0xb1, 0x8b, 0x3c, 0x58, 0x5, 0xe4, 0x40, 0xb8, 0x38, 0x45, 0x18, 0x60, 0x5c, 0x84, 0x30, 0x59, 0xa, 0xa0, 0x80, 0x6e, 0xa, 0x86, 0x92, 0x2f, 0x8, 0x3, 0x0, 0x69, 0xc8, 0x86, 0x87, 0x72, 0xca, 0x85, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char line_edit_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xd, 0xf6, 0xb4, 0x61, 0xf5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
+static const unsigned char line_edit_clear_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x90, 0x1, 0x6, 0xc0, 0x30, 0xc, 0x45, 0x77, 0x89, 0xd5, 0x76, 0xb3, 0x9e, 0x7b, 0x65, 0x63, 0xd, 0xf9, 0xbb, 0x48, 0x3b, 0xb3, 0x92, 0x54, 0x42, 0xb1, 0x5, 0x88, 0xf7, 0xc8, 0xcf, 0x9f, 0xfe, 0x1a, 0x8e, 0x14, 0xf4, 0x4e, 0x81, 0x63, 0x87, 0x51, 0x90, 0x28, 0x8, 0x46, 0x42, 0x51, 0x4a, 0x9e, 0x79, 0x43, 0xc5, 0x81, 0x55, 0x6f, 0xbc, 0x34, 0xdc, 0x2b, 0x2e, 0x16, 0xe5, 0x3a, 0xb1, 0xb, 0xb6, 0xca, 0x3, 0x2b, 0xb2, 0xc2, 0xbe, 0xf0, 0x66, 0x71, 0x4f, 0x70, 0x3b, 0x61, 0x14, 0x89, 0x26, 0x71, 0x5d, 0x6c, 0x9f, 0x1e, 0x17, 0x35, 0xae, 0xfa, 0xeb, 0xdc, 0x62, 0xc3, 0x84, 0x2d, 0x77, 0x22, 0xda, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char line_edit_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x95, 0xce, 0x31, 0x12, 0x2, 0x21, 0x10, 0x44, 0xd1, 0x3f, 0x40, 0xa1, 0x44, 0xa6, 0x46, 0xde, 0x63, 0x4f, 0xe5, 0x15, 0x38, 0xb2, 0xd6, 0x6, 0xb0, 0xc8, 0x30, 0x6, 0x96, 0xac, 0x56, 0x99, 0xf8, 0xb3, 0x7e, 0x51, 0xcb, 0xf9, 0x1a, 0xb3, 0x3f, 0xa, 0xaf, 0xc, 0xad, 0x2d, 0xcb, 0xe5, 0x76, 0x38, 0x5, 0x76, 0xec, 0x6c, 0xf7, 0xe0, 0x53, 0xe0, 0x13, 0xa1, 0x27, 0x27, 0x43, 0x26, 0x81, 0x20, 0xc8, 0x70, 0xfc, 0xe8, 0xf, 0x34, 0x67, 0xd8, 0x9c, 0x86, 0x61, 0x2e, 0x68, 0xe9, 0x91, 0xaf, 0x4b, 0x5a, 0x7d, 0x2a, 0x2c, 0x3, 0xed, 0xef, 0x1e, 0x6b, 0xcb, 0x4f, 0xa6, 0x66, 0x2b, 0x25, 0x6, 0x1, 0x37, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x94, 0xc8, 0x67, 0x6b, 0x60, 0xe6, 0x60, 0x64, 0x80, 0x80, 0xff, 0xc, 0x7f, 0x7f, 0xfc, 0x6a, 0x60, 0x94, 0xfb, 0xc0, 0xce, 0xcf, 0xc2, 0x80, 0x10, 0xfc, 0xc3, 0xf0, 0xf3, 0x23, 0xa3, 0xe2, 0x4f, 0xe, 0x36, 0x54, 0xc1, 0x1f, 0xbf, 0x18, 0x95, 0xbe, 0x73, 0x70, 0xb0, 0x30, 0xc0, 0x1, 0x48, 0xf0, 0x7, 0x85, 0x82, 0x58, 0x2d, 0xc2, 0xe6, 0xa4, 0x4f, 0x20, 0xc7, 0x37, 0x32, 0xb3, 0x23, 0x39, 0xfe, 0xfb, 0xaf, 0x46, 0x0, 0xee, 0x2a, 0x2f, 0xce, 0x4c, 0x47, 0x66, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char line_edit_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xab, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0xc8, 0x68, 0x12, 0xef, 0xed, 0xe7, 0xef, 0xed, 0xe8, 0xf0, 0xed, 0xe8, 0xf0, 0xee, 0xe8, 0xf0, 0xed, 0xe7, 0xed, 0xeb, 0xe5, 0xee, 0xeb, 0xe5, 0xee, 0xeb, 0xe6, 0xec, 0xe9, 0xe3, 0xeb, 0xe9, 0xe3, 0xeb, 0xe9, 0xe2, 0xec, 0xe9, 0xe2, 0xe9, 0xe6, 0xe0, 0xea, 0xe7, 0xe0, 0xea, 0xe7, 0xe1, 0xe8, 0xe4, 0xdd, 0xe8, 0xe5, 0xde, 0xe8, 0xe5, 0xdd, 0xe8, 0xe4, 0xde, 0xe6, 0xe2, 0xdb, 0xe6, 0xe3, 0xdb, 0xe6, 0xe3, 0xdc, 0xe7, 0xe2, 0xdb, 0xe7, 0xe3, 0xdb, 0xe4, 0xe0, 0xd8, 0xe5, 0xe0, 0xd8, 0xe5, 0xe1, 0xd9, 0xe5, 0xe0, 0xd9, 0xe4, 0xe1, 0xd9, 0xe5, 0xe1, 0xd8, 0xe4, 0xe0, 0xd9, 0xe2, 0xdf, 0xd6, 0xe3, 0xdf, 0xd6, 0xe3, 0xde, 0xd6, 0xe2, 0xde, 0xd6, 0xe1, 0xdc, 0xd4, 0xe1, 0xdc, 0xd3, 0xe0, 0xdc, 0xd3, 0xe1, 0xdd, 0xd3, 0xe1, 0xdd, 0xd4, 0xdf, 0xda, 0xd0, 0xdf, 0xda, 0xd1, 0xdf, 0xdb, 0xd1, 0xe0, 0xda, 0xd1, 0xdd, 0xd8, 0xcf, 0xdd, 0xd8, 0xce, 0xde, 0xd9, 0xce, 0xde, 0xd8, 0xce, 0xdd, 0xd9, 0xce, 0xdc, 0xd6, 0xcc, 0xdb, 0xd6, 0xcc, 0xdc, 0xd6, 0xcb, 0xff, 0xff, 0xff, 0x73, 0x72, 0x65, 0x6f, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x36, 0x61, 0xc5, 0x3a, 0xd, 0x83, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x38, 0xa0, 0x7, 0xa5, 0xd6, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x9e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x5d, 0xcf, 0xdb, 0x16, 0x82, 0x20, 0x10, 0x85, 0x61, 0xb4, 0xb4, 0x13, 0x1d, 0x28, 0x14, 0xcb, 0x4a, 0x33, 0xf, 0x59, 0x52, 0x98, 0x62, 0xef, 0xff, 0x66, 0xd1, 0xf6, 0xca, 0xfe, 0x19, 0xd6, 0x62, 0x7d, 0x77, 0x43, 0x88, 0x3d, 0x88, 0x10, 0x7b, 0x34, 0xc8, 0x36, 0x30, 0x76, 0x1c, 0x77, 0xe2, 0x3a, 0xee, 0xd4, 0x7c, 0x0, 0xb3, 0x79, 0x3f, 0xa6, 0x5, 0x80, 0xa2, 0x25, 0xa5, 0xab, 0x35, 0x5, 0x6c, 0x18, 0x63, 0x5b, 0xd6, 0x7, 0xd8, 0x71, 0xcf, 0xe3, 0x9c, 0xfb, 0x9c, 0x7b, 0x3e, 0x40, 0x4, 0xfb, 0xe0, 0x10, 0x84, 0xa1, 0x8, 0x85, 0x0, 0x1c, 0x4f, 0xe7, 0x28, 0xbe, 0x44, 0x71, 0x9c, 0x24, 0x67, 0xc0, 0x35, 0x4d, 0xb3, 0x2c, 0xcb, 0xcd, 0x4b, 0x73, 0x40, 0x71, 0x33, 0x15, 0xe5, 0xfd, 0x51, 0x16, 0x25, 0xa0, 0x92, 0xf2, 0xf9, 0x92, 0xbf, 0x2a, 0x9, 0x50, 0xaa, 0x56, 0xef, 0x46, 0xb5, 0x4d, 0x5b, 0x37, 0x0, 0xdd, 0x7d, 0xb4, 0x36, 0xdb, 0x69, 0xad, 0x1, 0x7f, 0xc7, 0x59, 0xc3, 0xf3, 0xad, 0x2f, 0x30, 0x4f, 0x11, 0x50, 0x3e, 0x12, 0x48, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xa8, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0xc8, 0x68, 0x12, 0xef, 0xed, 0xe7, 0xef, 0xed, 0xe8, 0xf0, 0xed, 0xe8, 0xf0, 0xee, 0xe8, 0xf0, 0xed, 0xe7, 0xed, 0xeb, 0xe5, 0xee, 0xeb, 0xe5, 0xee, 0xeb, 0xe6, 0xec, 0xe9, 0xe3, 0xeb, 0xe9, 0xe3, 0xeb, 0xe9, 0xe2, 0xec, 0xe9, 0xe2, 0xe9, 0xe6, 0xe0, 0xea, 0xe7, 0xe0, 0xea, 0xe7, 0xe1, 0xe8, 0xe4, 0xdd, 0xe8, 0xe5, 0xde, 0xe8, 0xe5, 0xdd, 0xe8, 0xe4, 0xde, 0xe6, 0xe2, 0xdb, 0xe6, 0xe3, 0xdb, 0xe6, 0xe3, 0xdc, 0xe7, 0xe2, 0xdb, 0xe7, 0xe3, 0xdb, 0xe4, 0xe0, 0xd8, 0xe5, 0xe0, 0xd8, 0xe5, 0xe1, 0xd9, 0xe5, 0xe0, 0xd9, 0xe4, 0xe1, 0xd9, 0xe5, 0xe1, 0xd8, 0xe4, 0xe0, 0xd9, 0xe2, 0xdf, 0xd6, 0xe3, 0xdf, 0xd6, 0xe3, 0xde, 0xd6, 0xe2, 0xde, 0xd6, 0xe1, 0xdc, 0xd4, 0xe1, 0xdc, 0xd3, 0xe0, 0xdc, 0xd3, 0xe1, 0xdd, 0xd3, 0xe1, 0xdd, 0xd4, 0xdf, 0xda, 0xd0, 0xdf, 0xda, 0xd1, 0xdf, 0xdb, 0xd1, 0xe0, 0xda, 0xd1, 0xdd, 0xd8, 0xcf, 0xdd, 0xd8, 0xce, 0xde, 0xd9, 0xce, 0xde, 0xd8, 0xce, 0xdd, 0xd9, 0xce, 0xdc, 0xd6, 0xcc, 0xdb, 0xd6, 0xcc, 0xdc, 0xd6, 0xcb, 0xbd, 0x92, 0xbc, 0xa2, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x36, 0x61, 0xc5, 0x3a, 0xd, 0x83, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x4c, 0x8c, 0x55, 0x2, 0x4, 0x1, 0x8, 0x85, 0xc0, 0xc9, 0xfb, 0x1f, 0x76, 0x7b, 0x75, 0x3a, 0xf0, 0xc7, 0xc0, 0x27, 0xc1, 0x9d, 0x34, 0xe4, 0x4e, 0xb5, 0xa0, 0x68, 0x95, 0xf1, 0x93, 0xc4, 0xb0, 0xb7, 0xd6, 0x2, 0x7c, 0x2d, 0x46, 0xc3, 0x82, 0x45, 0xf8, 0x87, 0x16, 0x5a, 0xd7, 0x71, 0x21, 0x9e, 0x2c, 0x86, 0x52, 0x10, 0x89, 0xee, 0x86, 0x15, 0xd9, 0xf0, 0x6b, 0x7f, 0xac, 0x8b, 0xce, 0x85, 0xb4, 0x8b, 0xe1, 0xb7, 0x2e, 0x6, 0xd9, 0x53, 0x6a, 0x3c, 0x43, 0xa9, 0xd0, 0xcc, 0xd8, 0x5f, 0xd0, 0x4, 0xa2, 0xf6, 0x50, 0xac, 0x68, 0xff, 0x6d, 0xf9, 0x3f, 0xc, 0x93, 0x88, 0x59, 0x68, 0x81, 0x69, 0x18, 0x9e, 0x3, 0xba, 0x1b, 0x55, 0x0, 0x0, 0x0, 0x69, 0x26, 0x8d, 0xeb, 0x4b, 0xad, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char logo_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc3, 0x3e, 0x61, 0xcb, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x2e, 0x23, 0x0, 0x0, 0x2e, 0x23, 0x1, 0x78, 0xa5, 0x3f, 0x76, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdc, 0x9, 0x7, 0x13, 0x2, 0x0, 0x15, 0xb9, 0x53, 0x97, 0x0, 0x0, 0x21, 0x58, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x7d, 0x79, 0x9c, 0x1c, 0x55, 0xb5, 0xff, 0xf7, 0x7b, 0xab, 0x7b, 0x66, 0x48, 0x8, 0x61, 0xd1, 0x90, 0xb0, 0x88, 0x91, 0x27, 0x24, 0x24, 0x21, 0x3b, 0x8, 0x4, 0x42, 0x58, 0x54, 0xe0, 0x91, 0x80, 0x24, 0x1, 0x2, 0x9, 0x42, 0x80, 0x4, 0x11, 0x90, 0x9f, 0xf2, 0xd3, 0xa7, 0xcf, 0xe7, 0xf3, 0x3d, 0x1f, 0x1f, 0x7f, 0xea, 0xd3, 0x48, 0x4c, 0x8, 0x61, 0xd, 0x49, 0x64, 0x89, 0x82, 0x40, 0x58, 0x4, 0x64, 0xb, 0x44, 0x25, 0x9b, 0xd9, 0x51, 0x14, 0x41, 0x3, 0xc8, 0x16, 0x20, 0xfb, 0x4c, 0x77, 0xdd, 0xef, 0xef, 0x8f, 0xaa, 0xea, 0xae, 0xee, 0xa9, 0xea, 0x9e, 0xee, 0xae, 0x99, 0xe9, 0xe0, 0x9c, 0xf9, 0xd4, 0x74, 0xd5, 0xad, 0x5b, 0x77, 0x39, 0xe7, 0xdc, 0x7b, 0xcf, 0x39, 0xf7, 0xdc, 0x7b, 0x81, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xf8, 0xe7, 0x2, 0x76, 0x76, 0x1, 0xea, 0x1, 0xe, 0xff, 0xc2, 0xcc, 0xbd, 0x60, 0x5b, 0x6e, 0xb6, 0xd6, 0xf6, 0x2, 0xb8, 0x8d, 0xc6, 0x6c, 0x36, 0x34, 0x6f, 0x81, 0x7c, 0x43, 0x30, 0x7f, 0x27, 0xcd, 0xdf, 0x8c, 0xe3, 0x6c, 0xda, 0x70, 0xef, 0xf4, 0x37, 0x3b, 0xbb, 0xac, 0x49, 0x43, 0xaa, 0xb3, 0xb, 0x50, 0xf, 0x20, 0x9b, 0xfd, 0x96, 0xcd, 0xb6, 0x4c, 0x40, 0xd0, 0x20, 0x2c, 0xac, 0x4b, 0xb3, 0x3, 0xc0, 0x36, 0x80, 0x5b, 0x41, 0x6c, 0x75, 0x5b, 0xb8, 0xed, 0xb0, 0x71, 0xff, 0xbb, 0x83, 0xc6, 0x6c, 0x26, 0x9d, 0x65, 0x74, 0xd2, 0x4f, 0x6e, 0x5c, 0x74, 0xc5, 0xba, 0xce, 0x2e, 0x7b, 0xad, 0xf0, 0x4f, 0xdf, 0x3, 0xf4, 0x9f, 0x38, 0xb7, 0x5b, 0x76, 0xd7, 0x7, 0x2f, 0xcb, 0xda, 0x3, 0xc8, 0x42, 0x94, 0x48, 0x6a, 0x15, 0x9f, 0x24, 0x0, 0xbe, 0x43, 0xe3, 0xfc, 0xc1, 0x49, 0x37, 0x4d, 0xdd, 0xf8, 0x8b, 0x2b, 0xff, 0xde, 0xd9, 0x75, 0xa8, 0x5, 0x76, 0x2b, 0x6, 0xe8, 0x37, 0x7e, 0xf6, 0x18, 0xeb, 0xb6, 0x9c, 0x6, 0x69, 0xf, 0x1a, 0xf3, 0xc1, 0x1f, 0xef, 0xbb, 0xe6, 0xdb, 0xb5, 0xa4, 0x37, 0xf2, 0x9a, 0xa5, 0xdc, 0xb2, 0x69, 0xe5, 0x69, 0xca, 0xec, 0xf8, 0xa5, 0xa4, 0x26, 0x48, 0xf2, 0x29, 0x8c, 0x82, 0x7b, 0x40, 0x3e, 0xae, 0xfc, 0x5f, 0x41, 0x82, 0x4d, 0x37, 0xf5, 0x18, 0xb7, 0xd7, 0xc1, 0xc3, 0x1f, 0xfe, 0xfd, 0x4f, 0x3e, 0xa3, 0x2a, 0x8b, 0xd0, 0xe9, 0x50, 0xf7, 0xc, 0x70, 0xf8, 0x39, 0xb3, 0x3e, 0x9, 0xb9, 0xa7, 0x48, 0xf6, 0x70, 0xb9, 0xd9, 0xd1, 0x90, 0x3b, 0xd2, 0x2b, 0x39, 0x9b, 0x4d, 0xaa, 0x69, 0xfa, 0x1f, 0xef, 0xbb, 0xfa, 0x8e, 0x5a, 0xd2, 0x3f, 0x6c, 0xdc, 0x8f, 0x9f, 0x91, 0xcd, 0x8c, 0x2, 0xe9, 0xe4, 0x43, 0x3, 0x7a, 0xc7, 0x80, 0x4, 0x80, 0xbb, 0x9c, 0x74, 0xd3, 0x77, 0xdd, 0xcc, 0xce, 0x1f, 0xbc, 0xfc, 0xd0, 0xd7, 0x6d, 0x67, 0xe3, 0xa9, 0x5a, 0xa8, 0x5b, 0x19, 0xa0, 0xdf, 0xf8, 0xd9, 0x47, 0x42, 0xee, 0x51, 0x72, 0x5b, 0x3e, 0x6b, 0xdd, 0xcc, 0x69, 0x0, 0xf6, 0xf4, 0x8, 0xe3, 0x75, 0xc3, 0x92, 0x1a, 0x6d, 0x66, 0xd7, 0x8f, 0xfa, 0x8d, 0x9f, 0xf5, 0xe7, 0x97, 0x7e, 0x71, 0xe5, 0xf3, 0x55, 0xe5, 0x31, 0xe1, 0xc6, 0x83, 0xdc, 0x5d, 0x5b, 0x46, 0x3, 0x7e, 0xb3, 0xce, 0x51, 0xbd, 0x74, 0xbb, 0xf0, 0x9b, 0xbb, 0x23, 0xd9, 0x23, 0x59, 0xf7, 0x4d, 0xa8, 0x34, 0xd4, 0x1d, 0x3, 0xf4, 0x3b, 0x67, 0xf6, 0x20, 0xc0, 0x1d, 0x65, 0xb3, 0xcd, 0x67, 0xc9, 0xcd, 0x9c, 0xa, 0x9f, 0x1a, 0xfe, 0xd8, 0x5b, 0xd0, 0x15, 0xb, 0xda, 0xcf, 0x66, 0x9a, 0x7f, 0xd8, 0x7f, 0xc2, 0x9c, 0xb1, 0x1b, 0x17, 0x4d, 0x7f, 0xa7, 0x92, 0x7c, 0xe, 0xff, 0xc2, 0xd, 0x69, 0x58, 0x77, 0x1c, 0x40, 0x17, 0x84, 0x3, 0x54, 0x48, 0x4a, 0xd2, 0x91, 0x75, 0x7, 0x38, 0x4d, 0x7b, 0xef, 0xd6, 0x2c, 0x50, 0x37, 0xc, 0xd0, 0x7f, 0xc2, 0x8d, 0x7, 0x3, 0x1a, 0x65, 0x33, 0xcd, 0x97, 0x58, 0x9b, 0x3d, 0x5, 0x0, 0x40, 0xe6, 0x5a, 0xa6, 0x82, 0x47, 0xbf, 0x13, 0x0, 0x21, 0x82, 0x90, 0xdc, 0xcf, 0xc8, 0x66, 0xbe, 0xd6, 0x6f, 0xfc, 0xac, 0xef, 0xbc, 0xf4, 0x8b, 0x2b, 0x77, 0xb5, 0x35, 0x3f, 0x93, 0x6a, 0xb4, 0x36, 0xb3, 0xe3, 0x7c, 0x1a, 0xe3, 0x8f, 0xe9, 0xe1, 0x21, 0x3f, 0x4, 0xe1, 0xd1, 0x40, 0x80, 0x24, 0xd1, 0x90, 0x10, 0x8c, 0x64, 0xf, 0x31, 0xa9, 0xa6, 0x2e, 0x6, 0x48, 0x2, 0x64, 0xb3, 0xdf, 0xb0, 0xd9, 0xe6, 0x2f, 0x1, 0x41, 0x6b, 0xf7, 0x9, 0x2f, 0x91, 0x1e, 0x23, 0x78, 0x40, 0x9f, 0x8, 0x34, 0x41, 0x90, 0x75, 0x33, 0xbb, 0xfe, 0xaf, 0xd3, 0xd0, 0x7d, 0xd9, 0x61, 0xe3, 0x7e, 0x78, 0xdf, 0x9f, 0x1e, 0xb8, 0x2e, 0x72, 0x3c, 0x1e, 0x30, 0xe9, 0xce, 0x94, 0xdb, 0xb2, 0x7d, 0x1f, 0xd2, 0xf4, 0x0, 0x6c, 0x1a, 0xb2, 0xbd, 0x65, 0xdd, 0xcf, 0x0, 0x30, 0x0, 0x41, 0x42, 0x91, 0xbd, 0x0, 0xb, 0xef, 0x49, 0x52, 0x9e, 0x7a, 0x40, 0x48, 0x7b, 0xee, 0x6, 0x62, 0x54, 0x49, 0xa8, 0x1b, 0x6, 0xb0, 0xd9, 0xcc, 0x39, 0x7e, 0x6b, 0xb, 0xda, 0x5c, 0xa8, 0xeb, 0x2f, 0x4, 0x7a, 0x81, 0x41, 0x3c, 0x3, 0x10, 0x36, 0xbb, 0xeb, 0xc7, 0x4e, 0x43, 0x8f, 0xd7, 0xfa, 0x4f, 0xb8, 0x71, 0x3, 0x68, 0xf6, 0x7, 0xb0, 0x37, 0x81, 0x34, 0x8, 0xca, 0xda, 0x46, 0xb7, 0x65, 0xeb, 0x27, 0x20, 0x3b, 0xd8, 0x75, 0xdd, 0xbe, 0x4, 0xf6, 0x83, 0x74, 0x30, 0x80, 0x40, 0xf0, 0x53, 0x25, 0x43, 0x0, 0xfd, 0xff, 0x22, 0xad, 0xcd, 0xee, 0xac, 0x59, 0x3, 0xe8, 0x7f, 0xee, 0x2d, 0xdd, 0x36, 0xde, 0x73, 0xe9, 0x8e, 0xce, 0xc0, 0x7b, 0xdd, 0x30, 0x0, 0x8d, 0xf3, 0xb2, 0xac, 0x3e, 0xe, 0xc0, 0x20, 0x4e, 0xc, 0xf, 0xc8, 0x1e, 0x3c, 0xf9, 0x8a, 0x3a, 0x49, 0x40, 0xf6, 0x60, 0xeb, 0xb6, 0xfc, 0x1f, 0xd2, 0xac, 0xb3, 0xb6, 0xf9, 0x24, 0x78, 0xad, 0xbb, 0x9b, 0x17, 0xb5, 0x90, 0x46, 0xca, 0x25, 0x46, 0x85, 0x52, 0x8e, 0xcb, 0xa7, 0x30, 0xdc, 0x4a, 0xa0, 0x21, 0xe8, 0x7d, 0xed, 0x36, 0x6f, 0xad, 0x89, 0x1, 0x8e, 0x38, 0x77, 0x6e, 0x5f, 0xeb, 0xb6, 0x9c, 0xde, 0x7f, 0xc2, 0x9c, 0xe7, 0x36, 0x2e, 0x9a, 0xbe, 0xb6, 0xc3, 0xf1, 0xde, 0xd1, 0x19, 0xc6, 0x41, 0xff, 0x9, 0xb3, 0xbf, 0x67, 0x33, 0xcd, 0x5f, 0x96, 0x6c, 0xcf, 0x70, 0xab, 0x8f, 0xa3, 0x43, 0x41, 0xb8, 0x4, 0x90, 0x16, 0x80, 0x41, 0xd8, 0x78, 0x43, 0x6, 0xef, 0x8a, 0xf4, 0x7a, 0x9, 0xf2, 0xfa, 0x7d, 0xff, 0xb1, 0x40, 0x0, 0x60, 0x51, 0xde, 0xc5, 0xf9, 0x11, 0x39, 0x23, 0x51, 0xd6, 0x69, 0xdc, 0xf3, 0x18, 0xc9, 0xbe, 0x61, 0x9c, 0x86, 0xad, 0x1b, 0xee, 0x9e, 0xba, 0xb5, 0xad, 0xf5, 0x3d, 0xe2, 0xbc, 0x5b, 0xbb, 0xc1, 0xba, 0x9f, 0xc8, 0x66, 0xb6, 0x2f, 0x86, 0x74, 0x28, 0x80, 0xb7, 0x4d, 0xba, 0xdb, 0xb9, 0xc6, 0x38, 0x4b, 0x37, 0xdc, 0x73, 0x59, 0x4b, 0x47, 0xe1, 0xbd, 0x6e, 0x18, 0xa0, 0xdf, 0x84, 0x39, 0xa7, 0x2b, 0xb3, 0x73, 0x2e, 0xa0, 0x3, 0x81, 0x60, 0x9c, 0x6f, 0x73, 0xb7, 0x1c, 0xc8, 0xb, 0x20, 0xf3, 0xad, 0x3a, 0xf4, 0x9c, 0x78, 0x3d, 0x95, 0x37, 0x13, 0x92, 0xc6, 0xf9, 0xb, 0x9d, 0xf4, 0x22, 0x63, 0x52, 0xb7, 0x3, 0x78, 0x3d, 0xdb, 0xbc, 0x6d, 0xe7, 0x9f, 0x1e, 0xf8, 0x6a, 0xac, 0x6d, 0xa0, 0xff, 0x84, 0x39, 0xfb, 0x4b, 0xee, 0x14, 0x9b, 0x69, 0xfe, 0x41, 0x90, 0x9a, 0x2f, 0x5b, 0xc0, 0xa4, 0x9b, 0xfe, 0xcd, 0x18, 0xe7, 0x96, 0xd, 0xf7, 0x4e, 0x7f, 0xb7, 0x23, 0xf0, 0x5e, 0x37, 0xc, 0xd0, 0xff, 0xdc, 0x9b, 0x3f, 0x65, 0x5b, 0xb6, 0x3f, 0x21, 0xd9, 0x4f, 0x41, 0x8, 0x24, 0xed, 0xb6, 0x95, 0x56, 0x65, 0xde, 0x25, 0x55, 0x53, 0x3f, 0xad, 0x9c, 0x26, 0xe0, 0x3f, 0x14, 0xf4, 0x1e, 0x26, 0x75, 0x3f, 0x9d, 0x86, 0x9f, 0xd2, 0x49, 0xaf, 0xec, 0xd1, 0xfb, 0x88, 0x6d, 0xc5, 0x56, 0xc2, 0xfe, 0x13, 0x6f, 0x3a, 0xcc, 0x66, 0x9b, 0xe7, 0x40, 0xee, 0x18, 0x0, 0x5e, 0xaf, 0x15, 0x24, 0x3, 0x8, 0x24, 0x8d, 0xd3, 0x70, 0x13, 0x4c, 0xea, 0xfb, 0x1b, 0xef, 0x9d, 0xf6, 0x6a, 0x7b, 0xe3, 0xdd, 0xb4, 0x77, 0x6, 0x6d, 0x85, 0x8d, 0xf7, 0x5c, 0xf6, 0xa, 0x69, 0x9a, 0x3d, 0x51, 0x3b, 0xc0, 0x26, 0xfd, 0xb, 0xa5, 0x9, 0x58, 0xaa, 0xa3, 0x28, 0xf7, 0x6d, 0x25, 0xe0, 0xa7, 0x95, 0x27, 0x3e, 0x94, 0xcf, 0xc0, 0xd3, 0x26, 0xad, 0x9b, 0x3d, 0xdb, 0x6d, 0xd9, 0xf1, 0x8c, 0x6d, 0xd9, 0xfe, 0xdc, 0x96, 0xd7, 0x57, 0x9f, 0x11, 0xfe, 0xfc, 0x88, 0x73, 0xe7, 0x9e, 0xec, 0xb6, 0xec, 0xd8, 0x28, 0xeb, 0x8e, 0xf1, 0xbe, 0xf5, 0xf1, 0x2f, 0x88, 0xa0, 0xcf, 0x48, 0xb4, 0xd6, 0x6d, 0x99, 0x66, 0xb3, 0x2d, 0xf3, 0xfb, 0x4f, 0x9c, 0x7b, 0x5c, 0x7b, 0xe3, 0xbd, 0x6e, 0x7a, 0x0, 0x0, 0xe8, 0x77, 0xce, 0xcf, 0x9e, 0xb3, 0x6e, 0xe6, 0x78, 0x20, 0x5a, 0xfa, 0xaf, 0x3f, 0x8, 0x86, 0x81, 0x7c, 0x61, 0xfd, 0x91, 0x41, 0x64, 0xa0, 0x5a, 0x38, 0x2b, 0x4c, 0xba, 0xf1, 0x3b, 0x4, 0x7a, 0x66, 0x5b, 0x76, 0x2c, 0xf4, 0xf8, 0xbb, 0xd5, 0xb0, 0x54, 0xd0, 0x4f, 0x5, 0x6a, 0x26, 0x8d, 0x79, 0x8d, 0x4e, 0xd3, 0xbf, 0xbd, 0xb4, 0x68, 0xda, 0x5d, 0xed, 0x55, 0x3, 0xa7, 0xf6, 0x24, 0x92, 0x83, 0x8f, 0xf, 0x1c, 0x9b, 0x2, 0x34, 0x9c, 0x40, 0x8f, 0x78, 0xcb, 0x4c, 0x3d, 0x41, 0xd0, 0x45, 0xf9, 0xe0, 0xcb, 0x2d, 0xbe, 0xd5, 0x92, 0x14, 0x24, 0xa2, 0xb7, 0x6c, 0x76, 0x82, 0xac, 0x7b, 0x16, 0x29, 0x27, 0x50, 0x21, 0x1, 0x85, 0xba, 0xba, 0x5c, 0x37, 0xe2, 0xdb, 0xbb, 0x72, 0x36, 0xb0, 0xbd, 0x61, 0xdd, 0x13, 0xf7, 0x3f, 0xf2, 0xec, 0x96, 0x77, 0xd6, 0x2f, 0xfe, 0x5d, 0x7b, 0xd4, 0xa0, 0x6e, 0x86, 0x0, 0xaf, 0x34, 0xce, 0x12, 0x0, 0xef, 0x7b, 0xf7, 0x86, 0xf9, 0x21, 0x60, 0x37, 0xb9, 0x8c, 0xf1, 0x94, 0xc3, 0x80, 0x71, 0x69, 0x40, 0xd2, 0x90, 0x6c, 0x0, 0xd4, 0x0, 0x18, 0x79, 0x17, 0x8, 0x18, 0x45, 0xa4, 0xe1, 0x31, 0x81, 0x31, 0xfe, 0x7b, 0x3, 0x40, 0xfb, 0x65, 0x33, 0xbb, 0xbe, 0xde, 0x6f, 0xc2, 0x9c, 0xaf, 0xb4, 0x7, 0xca, 0xeb, 0xa6, 0x7, 0xe8, 0x3f, 0x71, 0xee, 0x4, 0x4f, 0x38, 0x52, 0x3f, 0xf8, 0xb6, 0x9e, 0xd0, 0xe8, 0xba, 0xfb, 0x5c, 0x44, 0xae, 0xfd, 0xe7, 0xee, 0x1, 0xbf, 0x67, 0x80, 0x7f, 0x11, 0xa1, 0x77, 0x45, 0xdf, 0x93, 0xa1, 0x74, 0x82, 0x1e, 0x61, 0x4f, 0xca, 0xe, 0xea, 0x35, 0xe8, 0x2c, 0xe7, 0x9d, 0xf5, 0x8b, 0x97, 0x26, 0x89, 0xf7, 0xba, 0x30, 0x4, 0xf5, 0x9f, 0x78, 0xd3, 0x2c, 0x9b, 0xdd, 0x75, 0x36, 0xa0, 0x3e, 0xde, 0x18, 0x69, 0x24, 0x28, 0x6c, 0x0, 0xde, 0x1d, 0x81, 0x31, 0xf7, 0x6d, 0x6, 0x6f, 0x14, 0xf4, 0x70, 0x21, 0xb0, 0x1b, 0xc8, 0xee, 0x49, 0x17, 0xb2, 0xd3, 0x19, 0xe0, 0xf0, 0x73, 0x66, 0x3d, 0xad, 0x6c, 0xcb, 0x48, 0x0, 0xdd, 0xbd, 0x39, 0x1e, 0xdf, 0x74, 0x53, 0xef, 0xc3, 0x7f, 0x87, 0x40, 0xce, 0xe4, 0xd, 0x1a, 0x67, 0xb5, 0x71, 0xd2, 0xd7, 0x27, 0x9d, 0x43, 0x62, 0xc, 0x70, 0xc4, 0xb9, 0x73, 0x7f, 0x24, 0x61, 0x1b, 0x8d, 0xf3, 0xd3, 0xd, 0x77, 0x4f, 0x7d, 0xbf, 0x5c, 0xfc, 0x81, 0x93, 0xee, 0xd8, 0x23, 0xdb, 0xb2, 0xe3, 0x31, 0xd9, 0xec, 0x9, 0x5e, 0x3f, 0x97, 0x13, 0x80, 0xbb, 0x88, 0xef, 0x83, 0x6f, 0xc0, 0x24, 0xe9, 0xbc, 0x63, 0x9c, 0xf4, 0xe2, 0x75, 0x3f, 0xbf, 0x38, 0x71, 0xb, 0x61, 0x22, 0x98, 0x3e, 0xe2, 0xbc, 0x5b, 0x47, 0xd8, 0xcc, 0xce, 0x7, 0x25, 0x75, 0xa3, 0x71, 0xd6, 0x80, 0xe6, 0x75, 0xd2, 0xfc, 0x99, 0xc6, 0x99, 0xb7, 0xe1, 0xee, 0xa9, 0x7f, 0x2e, 0x8e, 0xdf, 0xff, 0xdc, 0x5b, 0xe, 0x95, 0xdb, 0x72, 0x87, 0x6c, 0x76, 0x14, 0xe9, 0xab, 0xc2, 0x5e, 0x4d, 0xe1, 0x49, 0xc7, 0x51, 0xc5, 0x8c, 0x33, 0xb9, 0x87, 0xe7, 0x85, 0x54, 0xe2, 0x9b, 0x62, 0x3, 0x6f, 0xb9, 0xb4, 0x63, 0xb5, 0xb4, 0x88, 0xf0, 0xa8, 0xef, 0x2a, 0x29, 0x6f, 0xeb, 0x6f, 0x72, 0xbe, 0x67, 0x0, 0x41, 0xe7, 0x91, 0x74, 0xd3, 0x9e, 0xe3, 0xd7, 0x2e, 0x98, 0xb2, 0xb3, 0x1a, 0xfa, 0x94, 0x82, 0x9a, 0x19, 0xe0, 0x88, 0xf3, 0xe7, 0xf5, 0x50, 0x76, 0xc7, 0xc3, 0xb2, 0xee, 0x71, 0x80, 0x42, 0x5a, 0x85, 0xd9, 0x42, 0x63, 0xd6, 0x80, 0xce, 0x4a, 0x1a, 0xe7, 0x77, 0x26, 0x95, 0x7e, 0x74, 0xdd, 0x82, 0x29, 0x1f, 0x1c, 0x71, 0xfe, 0x6d, 0x43, 0x6c, 0x66, 0xd7, 0x4d, 0x90, 0x7b, 0x54, 0xa8, 0x18, 0xc2, 0x6e, 0x3e, 0xe0, 0x27, 0xa, 0xca, 0xd9, 0x1c, 0x9, 0x3a, 0xaf, 0x9a, 0x54, 0xc3, 0xbf, 0x6f, 0xb8, 0xfb, 0xd2, 0x85, 0xed, 0x91, 0x55, 0xcd, 0x43, 0x80, 0xdc, 0xe6, 0x1f, 0xcb, 0xba, 0xbe, 0xf1, 0xc6, 0x84, 0xed, 0xf0, 0x7b, 0xc9, 0xba, 0xa3, 0x0, 0x77, 0x94, 0xac, 0x73, 0x86, 0xac, 0x3b, 0xae, 0xff, 0xc4, 0xb9, 0x7f, 0x57, 0xb6, 0x79, 0x38, 0x64, 0x8f, 0xf2, 0x6c, 0xf4, 0xb9, 0x7e, 0xdf, 0x17, 0xf8, 0xca, 0xb5, 0xe0, 0xb6, 0x98, 0xf5, 0x2b, 0x69, 0x95, 0xc5, 0x3e, 0x9f, 0xe1, 0xfb, 0x72, 0x71, 0xdb, 0x52, 0xd6, 0xf0, 0x77, 0x71, 0xe5, 0x2c, 0xec, 0x11, 0x3c, 0xe9, 0x97, 0xb9, 0xf9, 0x26, 0x1a, 0xe7, 0xa9, 0xc6, 0x6e, 0x3d, 0xef, 0xa9, 0x95, 0x4e, 0x71, 0x50, 0x53, 0xab, 0x1b, 0x70, 0xfe, 0x6d, 0x5f, 0xb0, 0x99, 0x9d, 0xbf, 0x90, 0x37, 0x8b, 0x9f, 0xa3, 0x62, 0x48, 0x82, 0x97, 0x82, 0x3c, 0xa, 0x3c, 0xee, 0x68, 0x25, 0x85, 0xad, 0xfd, 0x5d, 0xad, 0x3f, 0x4, 0x9e, 0x25, 0x90, 0x34, 0x4e, 0xea, 0x45, 0x3a, 0xd, 0xd7, 0xad, 0xbf, 0xeb, 0xe2, 0xe7, 0xda, 0x2b, 0xaf, 0xaa, 0x7b, 0x80, 0x81, 0x93, 0xee, 0x38, 0xd8, 0xcd, 0xec, 0xfc, 0xbe, 0x2, 0xa3, 0x95, 0xef, 0x58, 0xc5, 0x90, 0xff, 0x4e, 0xce, 0x98, 0x27, 0x8, 0x26, 0x4f, 0x64, 0x8f, 0xf8, 0x7e, 0xb7, 0x5f, 0xcd, 0x5c, 0x5d, 0x12, 0xf3, 0x7b, 0xd5, 0xb0, 0x5e, 0xa9, 0x6f, 0x8a, 0x1c, 0xc7, 0x2b, 0xae, 0x47, 0xe1, 0x77, 0xde, 0x9d, 0x71, 0xee, 0x69, 0x4f, 0xe2, 0x3, 0x55, 0x5a, 0x2, 0x7, 0x4c, 0x9a, 0xd7, 0x60, 0x6d, 0xf6, 0x5a, 0x59, 0xfb, 0x69, 0x7f, 0xf2, 0xc6, 0x9b, 0x5d, 0x2f, 0x12, 0xdf, 0x73, 0xcf, 0x45, 0xe3, 0xbb, 0x37, 0xe7, 0x91, 0x73, 0xac, 0xa9, 0x1c, 0x2a, 0xfc, 0x46, 0x2a, 0xe8, 0x9f, 0x15, 0xfc, 0x13, 0x50, 0xe0, 0x3e, 0x20, 0x95, 0x49, 0xa8, 0xd4, 0xc4, 0x12, 0x8b, 0x7e, 0x2b, 0xad, 0x7, 0x8b, 0x5f, 0x30, 0x5e, 0x8e, 0x4c, 0x10, 0x2a, 0x66, 0x80, 0x81, 0x17, 0xce, 0x77, 0x20, 0x3b, 0xda, 0x66, 0x5b, 0xae, 0xcd, 0x9b, 0xc1, 0xc3, 0x53, 0x76, 0x9d, 0x7b, 0x29, 0x34, 0x43, 0xe7, 0xdf, 0xfb, 0x73, 0xed, 0x1e, 0x81, 0x25, 0xd0, 0x37, 0x34, 0xe4, 0xae, 0xe0, 0x1d, 0xa3, 0x6d, 0x73, 0xf2, 0xd3, 0xca, 0xdd, 0xb7, 0xff, 0xe5, 0x33, 0xa9, 0xdc, 0x2f, 0xc, 0x98, 0x74, 0xc7, 0xf1, 0xed, 0xc9, 0x0, 0x15, 0xb7, 0xbf, 0x41, 0x17, 0xce, 0xef, 0x93, 0x6d, 0xd9, 0xf9, 0x0, 0xac, 0x3b, 0xd2, 0xeb, 0xc0, 0xe3, 0x54, 0xb7, 0x4a, 0x8a, 0x50, 0x4a, 0x65, 0x2, 0x4a, 0xb, 0x5c, 0x39, 0xc8, 0x77, 0xa2, 0xa, 0xd4, 0xa7, 0x82, 0xb4, 0x3e, 0x0, 0xf9, 0x3e, 0x80, 0x6d, 0x0, 0x76, 0x92, 0xdc, 0x5, 0xd2, 0x42, 0x8, 0xe4, 0x91, 0x14, 0x80, 0x26, 0x9, 0xdd, 0x20, 0xbb, 0xf, 0xa0, 0x5e, 0x90, 0x6f, 0x2a, 0x67, 0x4c, 0x1e, 0x35, 0x6b, 0x2e, 0x11, 0xf5, 0x93, 0xe7, 0x13, 0x0, 0xc2, 0x42, 0x32, 0x34, 0xce, 0x93, 0x26, 0xd5, 0x78, 0xd9, 0xba, 0x85, 0x17, 0xbd, 0x5a, 0x5b, 0x5e, 0xa5, 0x4b, 0xd0, 0x26, 0x18, 0x7c, 0xc5, 0x33, 0xcc, 0x7e, 0xf8, 0xea, 0x19, 0x36, 0xb3, 0xf3, 0x21, 0x0, 0x16, 0x81, 0x12, 0x1f, 0xae, 0x8a, 0xe2, 0x13, 0x2d, 0x18, 0xf2, 0x22, 0x4, 0xe7, 0x3c, 0xef, 0x7, 0xe6, 0xaf, 0xfc, 0x87, 0xad, 0xc8, 0xee, 0x8b, 0x1d, 0xa, 0xd6, 0x8a, 0x84, 0xe6, 0x66, 0xfd, 0x98, 0x2d, 0x34, 0xce, 0x3f, 0x24, 0xbc, 0x4d, 0x9a, 0x4d, 0x30, 0x66, 0x1d, 0xc0, 0x97, 0x48, 0xfe, 0x15, 0xe0, 0x3b, 0x20, 0xdf, 0x23, 0xd4, 0xec, 0x5a, 0x65, 0xd2, 0xe9, 0x86, 0x46, 0xeb, 0x66, 0xba, 0x1, 0xd8, 0xd7, 0x5a, 0xdb, 0x7, 0xd2, 0x0, 0xc9, 0x8e, 0x24, 0x74, 0xb0, 0xa4, 0x8f, 0x1, 0x3a, 0x0, 0xb2, 0xfb, 0x86, 0xab, 0xc2, 0x90, 0xcf, 0x7a, 0x1, 0x33, 0xa8, 0x75, 0x7d, 0xa, 0xe4, 0xfd, 0x8, 0x33, 0x40, 0x41, 0x13, 0xa, 0x3b, 0xc6, 0x7a, 0x35, 0xb2, 0x74, 0x1a, 0xe6, 0x34, 0xef, 0xdc, 0x7e, 0xd5, 0x5f, 0x1e, 0xb8, 0x3a, 0xf1, 0x15, 0x48, 0x15, 0x9, 0x81, 0xee, 0x96, 0xbf, 0xd, 0x92, 0xdb, 0xf2, 0x7d, 0x80, 0xa0, 0x6f, 0xb0, 0xf7, 0xb0, 0x9f, 0x9b, 0xb7, 0x40, 0xde, 0x23, 0xab, 0x88, 0x82, 0xb9, 0xa7, 0xd0, 0xff, 0x1c, 0xc5, 0x43, 0x2c, 0xc3, 0xa8, 0xc6, 0xdb, 0x2a, 0x2c, 0xb0, 0x93, 0x4, 0x62, 0x86, 0xfc, 0x29, 0x78, 0x80, 0x7c, 0xf, 0x30, 0x9b, 0x4, 0xb3, 0x96, 0x4e, 0x6a, 0x71, 0x3a, 0xd5, 0xf0, 0xe0, 0xea, 0x3b, 0x27, 0x95, 0x33, 0xa0, 0xb4, 0x0, 0xd8, 0xa, 0xe0, 0x2d, 0x0, 0x1b, 0x1, 0x3c, 0x15, 0xbc, 0x18, 0x30, 0xe9, 0xce, 0x7e, 0xb2, 0x99, 0x89, 0x80, 0x8e, 0x83, 0xec, 0xa1, 0x92, 0x3d, 0x8, 0x42, 0x63, 0xa0, 0xc1, 0x7a, 0x79, 0x2a, 0x50, 0x79, 0x42, 0x66, 0xcc, 0xbc, 0xab, 0x40, 0x58, 0xd, 0xca, 0xd7, 0x3b, 0xa8, 0x17, 0xfc, 0x70, 0xbf, 0x4a, 0xfe, 0xa, 0x88, 0xc0, 0x30, 0x26, 0xc1, 0x48, 0xee, 0x99, 0x4d, 0xdd, 0xf7, 0x5a, 0xe, 0xe0, 0xf6, 0xa4, 0x19, 0xa0, 0xa2, 0x1e, 0x60, 0xe0, 0x5, 0x77, 0x9e, 0xea, 0x66, 0x76, 0x3e, 0x26, 0xc9, 0x84, 0xb1, 0xdf, 0x91, 0x10, 0xb2, 0x15, 0xcb, 0xd7, 0x32, 0x7c, 0xe, 0xe0, 0xfb, 0x24, 0xdf, 0xa2, 0x49, 0xdd, 0x6c, 0x1c, 0x67, 0xf6, 0xda, 0x5, 0x53, 0xda, 0xbc, 0x48, 0xa4, 0xad, 0x30, 0x60, 0xd2, 0xbc, 0x43, 0x21, 0xf7, 0xbb, 0x92, 0x1d, 0x29, 0xeb, 0x7e, 0x2, 0x52, 0x93, 0xbf, 0x4c, 0x2d, 0xd4, 0x10, 0x12, 0xad, 0x6b, 0xde, 0xa7, 0x91, 0xce, 0x12, 0xa6, 0xf6, 0x38, 0x75, 0xfd, 0xc2, 0xb, 0x9a, 0x93, 0xcc, 0xa3, 0x32, 0x6, 0x98, 0x7c, 0x57, 0xa3, 0xcd, 0x36, 0x9f, 0x23, 0xb7, 0xe5, 0x4e, 0x40, 0x4e, 0xe0, 0x80, 0xd9, 0x51, 0xf6, 0xfb, 0x80, 0xf8, 0x61, 0x84, 0x4b, 0xd8, 0x49, 0x60, 0x87, 0x49, 0x37, 0x7e, 0x7b, 0xdd, 0xc2, 0x8b, 0x6e, 0x6c, 0xf7, 0x42, 0x0, 0x18, 0x30, 0xf9, 0xee, 0x94, 0x32, 0xdb, 0xe7, 0xca, 0xba, 0xa7, 0x1, 0xda, 0x3f, 0xb7, 0x78, 0x25, 0xef, 0x26, 0x98, 0x38, 0x42, 0x24, 0xb9, 0x34, 0xa9, 0x7b, 0x36, 0xdc, 0x3d, 0xf5, 0x82, 0x24, 0xd3, 0xad, 0x5c, 0x8, 0x9c, 0xbc, 0x70, 0xf, 0xeb, 0x66, 0x2f, 0xb3, 0xd9, 0xe6, 0x19, 0xf0, 0xc7, 0x5b, 0x4f, 0x14, 0xc8, 0x69, 0x57, 0x25, 0xd2, 0x2c, 0x67, 0x15, 0xb, 0xc7, 0x29, 0xf2, 0xe5, 0xf7, 0xa7, 0x46, 0xe1, 0x59, 0x19, 0xe1, 0x79, 0xd2, 0x3a, 0x5b, 0x61, 0x9c, 0xdb, 0x68, 0x52, 0x5f, 0x5f, 0xbf, 0x70, 0x72, 0x87, 0xb9, 0x52, 0x7, 0x30, 0x70, 0xf2, 0xcf, 0xbb, 0xb9, 0x2d, 0xdb, 0x97, 0x41, 0xb6, 0x2f, 0xc0, 0x3d, 0x2, 0xe7, 0x64, 0x32, 0xf0, 0x48, 0xe, 0x44, 0xa4, 0x52, 0xe, 0xe6, 0xc5, 0x78, 0x88, 0x14, 0x72, 0x25, 0x89, 0xa0, 0x59, 0xed, 0xa4, 0x1a, 0x3f, 0xb7, 0x6e, 0xe1, 0x94, 0xb7, 0xc2, 0x2f, 0x47, 0x5e, 0xb3, 0x94, 0x3b, 0xdf, 0x7b, 0xc5, 0xd0, 0x69, 0xa0, 0xcd, 0x6c, 0x27, 0x4d, 0x9a, 0x0, 0xdd, 0x75, 0xb, 0x2e, 0x70, 0xcb, 0xd5, 0xa1, 0x2a, 0x2e, 0x1d, 0x34, 0xf9, 0xe7, 0x7b, 0x58, 0xb7, 0xe5, 0xdb, 0x36, 0xdb, 0xf2, 0x75, 0x2, 0x26, 0x34, 0xf0, 0x33, 0x69, 0x57, 0xae, 0x70, 0x97, 0xf, 0x8f, 0xf8, 0x2, 0x0, 0x63, 0xcc, 0x66, 0xa6, 0x1a, 0xc7, 0xae, 0x5b, 0x30, 0x39, 0x51, 0x7, 0x89, 0x6a, 0x60, 0xc0, 0xa4, 0x79, 0xd7, 0xd9, 0x6c, 0xf3, 0x37, 0x0, 0xed, 0xcb, 0xb0, 0x47, 0x50, 0x72, 0x26, 0xab, 0x80, 0xe9, 0x41, 0x93, 0x7a, 0x7e, 0xc3, 0xdd, 0x53, 0x8f, 0x1f, 0x34, 0xe5, 0xee, 0x46, 0x9b, 0x6d, 0xa6, 0x71, 0x1a, 0x9a, 0x24, 0xb7, 0x2f, 0xa4, 0x8f, 0x9, 0xea, 0x49, 0xa0, 0x87, 0xa4, 0x3, 0x69, 0x9c, 0x17, 0x20, 0xf7, 0xf9, 0x75, 0xb, 0x2f, 0xca, 0x94, 0x4a, 0xbc, 0xea, 0xc2, 0xd, 0xbc, 0x70, 0x61, 0x83, 0x6c, 0xf6, 0xdf, 0xe5, 0xb6, 0x7c, 0x13, 0x64, 0xb0, 0x20, 0x23, 0xbf, 0xd8, 0x22, 0x49, 0x8, 0x98, 0x4a, 0x82, 0xa4, 0xac, 0x71, 0x52, 0xcf, 0x3b, 0xd, 0xdd, 0xce, 0x5e, 0x33, 0xef, 0xbc, 0xf, 0x92, 0xcf, 0xac, 0x5a, 0x7c, 0x2c, 0x18, 0x63, 0xb3, 0xbb, 0xe6, 0xc9, 0xda, 0x83, 0x3d, 0x43, 0x17, 0x3, 0x49, 0xbe, 0xf6, 0x6, 0x91, 0x5f, 0xdc, 0x2, 0x1, 0xbb, 0x48, 0xf3, 0x1a, 0xa4, 0xde, 0x80, 0x7a, 0x2, 0x28, 0xd2, 0x81, 0x82, 0x7b, 0xae, 0x34, 0xa9, 0xc6, 0xeb, 0xd6, 0x2d, 0x9c, 0xfc, 0x54, 0xa9, 0xa4, 0xab, 0xf6, 0x9, 0x5c, 0xb7, 0xe0, 0x82, 0x16, 0xa7, 0xb1, 0xfb, 0x7f, 0x99, 0x54, 0xe3, 0x75, 0x4, 0xb2, 0x8, 0x69, 0x33, 0x89, 0x9b, 0x45, 0x7c, 0x24, 0x90, 0xcc, 0x1a, 0x27, 0xfd, 0xf0, 0xfa, 0xbb, 0x2e, 0x19, 0x53, 0x4f, 0xc4, 0xf7, 0xf0, 0x71, 0xe1, 0xd3, 0x26, 0xd5, 0x78, 0xa, 0xe9, 0x6c, 0x40, 0x41, 0xd9, 0x6b, 0x77, 0x6d, 0x43, 0xe1, 0x6f, 0x23, 0x64, 0xf, 0x3, 0xb4, 0x17, 0x8a, 0xde, 0x15, 0xde, 0x6b, 0x88, 0xa0, 0x7f, 0x29, 0x57, 0xee, 0x9a, 0x9c, 0x42, 0xd7, 0xdc, 0x3e, 0x3e, 0xeb, 0x34, 0x74, 0x9f, 0x69, 0x52, 0x4d, 0x53, 0x4, 0xbe, 0xdf, 0x76, 0x8b, 0x60, 0x18, 0x4a, 0x85, 0x31, 0xc7, 0xd6, 0x5e, 0xbf, 0x9f, 0x7a, 0x72, 0xfd, 0x5d, 0x17, 0x9f, 0x95, 0x18, 0xd5, 0x12, 0x86, 0x75, 0xb, 0x26, 0xff, 0xc9, 0x34, 0x34, 0x9d, 0x49, 0xe3, 0x2c, 0xf7, 0x2d, 0x8e, 0xfe, 0xf0, 0x15, 0x26, 0x63, 0x31, 0x59, 0x4b, 0x85, 0x79, 0xcf, 0x7e, 0x7, 0x2b, 0xd2, 0xc8, 0xf3, 0x31, 0xd, 0x2e, 0x8a, 0x34, 0xc1, 0xd4, 0x51, 0x51, 0x47, 0x6c, 0xc, 0x81, 0x4f, 0x7e, 0xea, 0xc2, 0x87, 0x4a, 0xf6, 0x3e, 0x35, 0x7b, 0x5, 0xaf, 0xbe, 0xfd, 0x9c, 0x2c, 0x53, 0xd, 0xf7, 0x93, 0xdc, 0x51, 0x64, 0xa, 0x29, 0x1, 0x51, 0xcc, 0x50, 0x18, 0x26, 0xbf, 0x1f, 0x83, 0xe7, 0x2b, 0x0, 0xe3, 0xa4, 0x9f, 0x6c, 0x49, 0xf7, 0x3a, 0xbd, 0xdd, 0xa8, 0x97, 0x10, 0xac, 0x9b, 0x7f, 0xc1, 0x2b, 0x26, 0xd5, 0x38, 0x85, 0xc6, 0x59, 0x82, 0xfc, 0xec, 0x28, 0xa2, 0x99, 0x1c, 0x65, 0xc2, 0xf2, 0xcf, 0xcc, 0xdb, 0xa9, 0xc3, 0xef, 0x99, 0x7f, 0x95, 0x8b, 0x27, 0x4f, 0x39, 0x12, 0xac, 0xcd, 0x9e, 0xd7, 0x9d, 0x1f, 0x4e, 0x2c, 0x55, 0xde, 0x44, 0xdc, 0xc2, 0x6d, 0x36, 0xd3, 0xf, 0x40, 0xda, 0xa3, 0x17, 0x13, 0x71, 0xe7, 0x26, 0xd, 0x5, 0x58, 0x6f, 0x4a, 0x3c, 0xfd, 0xa8, 0x93, 0x6e, 0x1a, 0xff, 0xf2, 0xbc, 0xd3, 0x77, 0x8b, 0xcd, 0x98, 0xd6, 0xce, 0xbf, 0x60, 0x23, 0x4c, 0x6a, 0x16, 0xe9, 0xbc, 0xec, 0x4d, 0x31, 0x18, 0xc9, 0x53, 0x97, 0x6a, 0xc6, 0x4b, 0x1b, 0x2e, 0x6, 0xb3, 0x6d, 0x90, 0xfa, 0xca, 0xaa, 0x7f, 0xfb, 0x33, 0x80, 0x9b, 0x99, 0x1, 0x70, 0xdf, 0x9a, 0x13, 0x2a, 0x4, 0x1, 0x34, 0x34, 0xce, 0x5a, 0x9a, 0xf4, 0xd, 0x6b, 0xe6, 0x9d, 0xf7, 0x61, 0x7b, 0x11, 0xac, 0x3d, 0x60, 0xfd, 0xc2, 0xc9, 0xf7, 0xc0, 0xa4, 0x6e, 0x7, 0xb9, 0xcd, 0xb7, 0x57, 0x75, 0x98, 0xd1, 0x2c, 0xbc, 0x48, 0x56, 0x50, 0x8f, 0x52, 0x71, 0x6b, 0x66, 0x80, 0x23, 0xa7, 0xdc, 0xb5, 0x17, 0x60, 0x87, 0x92, 0x48, 0xe5, 0xf5, 0xde, 0x44, 0xc4, 0x1e, 0x92, 0xdc, 0x42, 0x93, 0x5a, 0xb0, 0x76, 0xfe, 0xa4, 0xc7, 0x3a, 0xa, 0x79, 0x49, 0x82, 0x31, 0xce, 0x2c, 0x9a, 0xd4, 0xbd, 0xbe, 0x8d, 0x3a, 0x98, 0x25, 0x69, 0xf7, 0x19, 0xc5, 0x80, 0xf8, 0xbe, 0xf6, 0x7c, 0xe4, 0xc0, 0xc9, 0xb, 0x87, 0xc4, 0x96, 0xb1, 0x96, 0xa, 0x1e, 0x7d, 0xed, 0xef, 0x8, 0x72, 0x38, 0x80, 0xb4, 0x97, 0xa1, 0xd7, 0xcd, 0xd5, 0xd2, 0x83, 0xf9, 0x5, 0xf7, 0x2a, 0xe0, 0xa4, 0x1e, 0x0, 0x4d, 0xe2, 0xf6, 0xef, 0x8e, 0x82, 0xb5, 0xf3, 0x27, 0x6d, 0x31, 0x4e, 0xfa, 0x36, 0x18, 0x67, 0x29, 0xfc, 0x3e, 0xd9, 0x9f, 0xe9, 0xab, 0xc, 0x27, 0x11, 0xf7, 0x88, 0x9, 0xf7, 0x47, 0x1, 0xff, 0x3f, 0x1, 0x6b, 0x4f, 0x80, 0x74, 0x76, 0x5c, 0x19, 0x6b, 0x62, 0x80, 0x6d, 0xff, 0xd8, 0x48, 0xeb, 0x66, 0xcf, 0x25, 0x4d, 0xca, 0x2f, 0x51, 0xcd, 0xeb, 0x79, 0x7c, 0x75, 0x9f, 0xa0, 0x79, 0x15, 0x30, 0xf7, 0xaf, 0x9b, 0x3f, 0xa9, 0xa2, 0xdd, 0xbf, 0xea, 0xd, 0xd6, 0xde, 0x79, 0xfe, 0xb, 0x34, 0xa9, 0xc5, 0x0, 0x0, 0x1a, 0x11, 0xac, 0x58, 0x31, 0x64, 0xc4, 0x3d, 0x63, 0xc2, 0x8b, 0xf0, 0x28, 0x92, 0xd, 0x24, 0xfa, 0xc6, 0x95, 0xaf, 0x26, 0x6, 0x58, 0x7f, 0xd7, 0xc5, 0x56, 0x6e, 0x76, 0x2c, 0xa0, 0x34, 0x69, 0xc2, 0x5b, 0xaf, 0x54, 0x7e, 0x91, 0x81, 0xe4, 0xef, 0xf5, 0x22, 0xc6, 0x59, 0x44, 0x63, 0x1e, 0xef, 0x6c, 0x2, 0x26, 0x1, 0xa4, 0x59, 0x4c, 0x93, 0x7a, 0x12, 0xfe, 0x7e, 0x46, 0x28, 0x35, 0xc, 0xb0, 0xb6, 0x6, 0x54, 0x98, 0x16, 0x82, 0x6e, 0xb5, 0xf1, 0xd3, 0xe3, 0xe7, 0x46, 0xd2, 0xba, 0x26, 0x6, 0x18, 0x74, 0xd1, 0x3d, 0x7d, 0x41, 0xf4, 0xf6, 0xc4, 0x76, 0x28, 0xa7, 0xf2, 0x56, 0x39, 0xec, 0xfb, 0x92, 0x3f, 0x49, 0xf3, 0x16, 0x8d, 0xf3, 0xd4, 0xda, 0x3b, 0xcf, 0xdf, 0xde, 0xd9, 0xc4, 0x4b, 0x2, 0xd6, 0xde, 0x79, 0xfe, 0x5a, 0x3a, 0xa9, 0xf9, 0x5e, 0x25, 0x73, 0xe, 0x1f, 0x25, 0xc4, 0x9f, 0xda, 0x2f, 0xcf, 0xaf, 0xc4, 0x50, 0x9e, 0xf5, 0xb4, 0x67, 0x63, 0xb7, 0x1e, 0x7, 0x46, 0x95, 0xad, 0x6a, 0x6, 0x18, 0x7c, 0xc9, 0xfd, 0x29, 0x59, 0x3b, 0xa, 0xa0, 0x4d, 0xa2, 0xe4, 0x81, 0x1, 0x3, 0x20, 0x68, 0x9c, 0xf9, 0x34, 0xce, 0x8a, 0xce, 0x26, 0x5c, 0xa2, 0x40, 0xf3, 0x57, 0xd2, 0xbc, 0x8b, 0x76, 0x76, 0x9f, 0xb, 0x5c, 0xe2, 0xfc, 0x1d, 0x67, 0xe0, 0x73, 0xc3, 0xc1, 0x10, 0x3e, 0x1d, 0x55, 0xac, 0xaa, 0x19, 0x60, 0xf5, 0x6d, 0x67, 0x67, 0x9, 0x7d, 0x26, 0x34, 0xd3, 0x55, 0x93, 0x9a, 0xc3, 0xdc, 0x46, 0x4e, 0x0, 0x4d, 0x6a, 0xd9, 0x9a, 0x3b, 0x26, 0xee, 0xd6, 0x63, 0x7f, 0x31, 0x18, 0x63, 0xd6, 0x9b, 0x54, 0xc3, 0x6c, 0xff, 0x51, 0x91, 0x5b, 0x91, 0xd7, 0x0, 0x85, 0x3e, 0x9, 0x9e, 0x22, 0xe8, 0xd, 0xa5, 0xe6, 0x15, 0x3a, 0xa9, 0xfb, 0x49, 0xf3, 0x46, 0xd4, 0x77, 0x6d, 0xf6, 0x8, 0x1a, 0x74, 0xd1, 0xdd, 0x4d, 0xa4, 0xb3, 0xbf, 0xac, 0xed, 0x2b, 0xe8, 0x40, 0x2, 0x7b, 0x43, 0xee, 0x98, 0xdc, 0x86, 0x8d, 0xc9, 0xa8, 0xb9, 0x24, 0xb9, 0x9, 0xe0, 0xa6, 0x24, 0x91, 0x53, 0xf, 0xb0, 0xfa, 0xf6, 0x9, 0x9b, 0x7, 0x7f, 0x71, 0xd1, 0x43, 0x0, 0xfe, 0x3, 0x0, 0x61, 0x12, 0x30, 0xc1, 0x84, 0x26, 0x80, 0x48, 0x12, 0xb2, 0xca, 0xeb, 0x1, 0x7c, 0x97, 0xc6, 0x79, 0x96, 0x74, 0x16, 0x64, 0x65, 0x16, 0x6f, 0xb8, 0x73, 0x42, 0x36, 0x2a, 0x89, 0x58, 0x6, 0x18, 0x74, 0xd1, 0xbd, 0x3d, 0x21, 0x1d, 0xe, 0xe8, 0x40, 0x90, 0x7b, 0x41, 0xea, 0x25, 0x65, 0x8f, 0x90, 0x75, 0x8f, 0x83, 0xf4, 0xe9, 0x60, 0xe1, 0x7a, 0x68, 0x51, 0x67, 0xad, 0x1e, 0x31, 0x9e, 0x3b, 0x21, 0x53, 0x33, 0x4, 0xac, 0x69, 0x2f, 0x42, 0x74, 0x26, 0x8, 0xb0, 0xa0, 0x79, 0x1f, 0xd2, 0x3e, 0x9, 0x35, 0x97, 0xc0, 0x21, 0xc7, 0x73, 0x8e, 0x1, 0x29, 0x70, 0x33, 0xc9, 0x55, 0x34, 0xa9, 0x87, 0x8c, 0x93, 0x9a, 0xbf, 0xfa, 0xf6, 0xf1, 0x9b, 0x4b, 0x25, 0x11, 0xc9, 0x0, 0x83, 0xbf, 0xb8, 0x68, 0x7f, 0x2b, 0xf7, 0x7c, 0x59, 0x77, 0x3a, 0x64, 0xf, 0x2f, 0xcc, 0x33, 0xa7, 0xb0, 0x7b, 0x4e, 0xa, 0xf0, 0xf9, 0xad, 0xb6, 0x1e, 0x20, 0x67, 0x2c, 0x37, 0x8e, 0xf3, 0xfc, 0x9a, 0x3b, 0x26, 0x6e, 0x4b, 0x8, 0xe7, 0x75, 0x5, 0x92, 0xb6, 0x3, 0xf8, 0x33, 0x80, 0x91, 0x40, 0xa2, 0xdb, 0xd7, 0x51, 0xe0, 0x3f, 0xe8, 0x38, 0xaf, 0x11, 0xe6, 0x41, 0x90, 0x3f, 0x5d, 0x3b, 0xef, 0xdc, 0x36, 0x9, 0xd0, 0x31, 0x3d, 0x80, 0xc6, 0xcb, 0x75, 0xbf, 0x5, 0xe8, 0x63, 0x60, 0xd8, 0xf1, 0xb3, 0xc0, 0x41, 0x23, 0x34, 0x3f, 0xd1, 0x26, 0xb7, 0xed, 0x92, 0x15, 0xc8, 0xff, 0x7c, 0x74, 0xd7, 0x86, 0x93, 0x7c, 0x1b, 0x26, 0xf5, 0x88, 0x6c, 0x76, 0x24, 0x22, 0x5d, 0xca, 0x83, 0xa0, 0x72, 0x4b, 0x90, 0x82, 0x77, 0xca, 0xe1, 0x8d, 0x4e, 0xfa, 0x47, 0xae, 0xab, 0x19, 0x1b, 0x16, 0x9c, 0x57, 0xd6, 0xb, 0x28, 0xc, 0x91, 0x3, 0x91, 0x80, 0x5e, 0x0, 0x1a, 0xbc, 0x42, 0x7b, 0x53, 0x8f, 0x79, 0xe9, 0xd2, 0x14, 0x49, 0xb1, 0x40, 0xe9, 0xe7, 0x8a, 0x6c, 0x1, 0xbb, 0x4, 0x54, 0x54, 0x81, 0xdd, 0x9, 0xd6, 0xdc, 0x31, 0xe1, 0x7d, 0x1a, 0xe7, 0x49, 0x1f, 0x47, 0x11, 0xb6, 0x80, 0x0, 0x8a, 0x9f, 0x11, 0xf3, 0x2e, 0xf7, 0xed, 0x7, 0x80, 0xb9, 0xad, 0x52, 0xe2, 0x3, 0x31, 0x3d, 0x80, 0x64, 0xf, 0x0, 0xb0, 0x97, 0x37, 0xbf, 0xac, 0xfc, 0xc6, 0x36, 0xde, 0x5b, 0x54, 0xd6, 0x73, 0xb5, 0x69, 0x95, 0x6c, 0xb0, 0x2e, 0xe7, 0x1d, 0x82, 0x1d, 0xee, 0xdb, 0xd7, 0x91, 0x40, 0xf2, 0x3d, 0x1f, 0xaf, 0x3e, 0x46, 0x8b, 0x5b, 0x7d, 0x2e, 0x66, 0x4c, 0xa, 0xa1, 0xb5, 0x29, 0xc1, 0xa2, 0x8, 0xc3, 0xb4, 0xe3, 0x38, 0x4d, 0xd5, 0x94, 0x27, 0x7a, 0x8, 0x10, 0x7a, 0xe6, 0xed, 0xcb, 0xc5, 0x63, 0x55, 0xa5, 0x3d, 0x74, 0xb9, 0xf8, 0x61, 0x2c, 0xf0, 0x75, 0x10, 0x89, 0xbb, 0x73, 0xd7, 0x15, 0xd0, 0x8, 0x84, 0x65, 0x68, 0x51, 0x4d, 0x8, 0xf, 0x6d, 0x49, 0x20, 0x7f, 0x97, 0x1f, 0x2d, 0x53, 0x81, 0x3c, 0x56, 0x29, 0x44, 0x32, 0x0, 0x8d, 0x69, 0x90, 0x6b, 0xbd, 0x1d, 0x2c, 0x3b, 0x60, 0x1a, 0x33, 0xe7, 0xf2, 0x47, 0xf3, 0x6, 0xc0, 0x8f, 0x34, 0x3, 0x10, 0x70, 0x9, 0xbe, 0x2f, 0x69, 0xbf, 0x4, 0x51, 0x9b, 0xaa, 0x56, 0x9c, 0x4c, 0x68, 0x9f, 0xc0, 0x72, 0xe3, 0x15, 0x4b, 0xbe, 0xf3, 0x1a, 0x3, 0x41, 0xf2, 0x4d, 0x48, 0x1f, 0x69, 0x6, 0x10, 0xe0, 0xa, 0xfc, 0xb0, 0xd0, 0xc1, 0x27, 0x6a, 0xfc, 0x8f, 0xc3, 0x1d, 0xc3, 0x69, 0xe5, 0xce, 0x2f, 0xaa, 0xd6, 0x1b, 0x37, 0x46, 0xb, 0xc8, 0xa9, 0x7a, 0x68, 0xd5, 0xfb, 0xc7, 0xa, 0xf8, 0x8c, 0x7e, 0x9f, 0xb, 0x63, 0xc9, 0xef, 0xe5, 0x2f, 0xa2, 0xfb, 0xe8, 0xea, 0x0, 0x7e, 0x3d, 0x73, 0xf5, 0x67, 0xcc, 0x6f, 0x14, 0xc4, 0x31, 0x41, 0x58, 0xbe, 0xaa, 0xe, 0x71, 0xd1, 0x43, 0x0, 0x0, 0x5, 0xd4, 0x8a, 0xcc, 0x3b, 0x1c, 0xa8, 0x88, 0xf7, 0x25, 0xca, 0xcf, 0xf0, 0x4d, 0x78, 0x55, 0x2c, 0x1, 0xe0, 0x0, 0xd0, 0x54, 0x25, 0xcc, 0xec, 0x2e, 0x40, 0xd2, 0x11, 0xb0, 0x77, 0x69, 0x7a, 0x85, 0x9, 0x1c, 0x77, 0xf, 0xd0, 0x3f, 0x5b, 0x43, 0x82, 0x6b, 0xad, 0xad, 0xca, 0xb4, 0x1c, 0xad, 0x5, 0x0, 0x2d, 0x79, 0xcb, 0x5e, 0x39, 0x83, 0x45, 0x2d, 0x4d, 0xb6, 0x90, 0x91, 0x8, 0xf4, 0x21, 0xf9, 0x91, 0x67, 0x0, 0x92, 0xfb, 0xb4, 0x6d, 0xb9, 0x0, 0xdb, 0x78, 0xaf, 0x6c, 0xb5, 0x64, 0x88, 0x1e, 0x2, 0xc8, 0xf, 0x19, 0xd8, 0xaa, 0xb, 0x8e, 0xef, 0x8, 0xfa, 0xe8, 0xfc, 0x26, 0x56, 0x5e, 0x9c, 0x10, 0x8f, 0x94, 0xdd, 0x46, 0xa5, 0x88, 0x9f, 0x7c, 0x63, 0xa6, 0x9f, 0xcf, 0x81, 0x0, 0x1a, 0x13, 0xc1, 0x74, 0xdd, 0x82, 0xf2, 0x7b, 0xa9, 0x28, 0x68, 0x5f, 0xc5, 0x50, 0xac, 0x71, 0x17, 0xf5, 0x94, 0x2c, 0x5a, 0x73, 0xe, 0x66, 0x43, 0x1b, 0x74, 0x55, 0x4, 0x91, 0x42, 0x20, 0x61, 0xde, 0x20, 0xb8, 0x85, 0xe1, 0x15, 0x27, 0x40, 0x91, 0x5c, 0x10, 0xb2, 0x7, 0x15, 0xcb, 0x9, 0xa5, 0x64, 0xc2, 0xe2, 0x97, 0x21, 0x9b, 0xa2, 0xa4, 0x8f, 0xeb, 0x23, 0xcf, 0x0, 0xec, 0x5, 0x20, 0xd8, 0x53, 0x0, 0x28, 0x25, 0xf4, 0x15, 0xc, 0x97, 0x21, 0x9c, 0x7, 0x32, 0x9a, 0x2f, 0x48, 0x12, 0xcc, 0x0, 0xa8, 0xea, 0xd0, 0xa9, 0x18, 0x4b, 0xa0, 0xde, 0x2, 0xd9, 0x82, 0x60, 0xc1, 0x81, 0xc7, 0xb6, 0x8, 0x76, 0x44, 0x60, 0x3b, 0xfc, 0xf9, 0x5a, 0x40, 0x13, 0xeb, 0x68, 0x3, 0xeb, 0xa4, 0x61, 0xf0, 0xd4, 0x5f, 0xed, 0x6b, 0xad, 0x7b, 0x8a, 0x8f, 0x57, 0x26, 0x85, 0x3b, 0x49, 0x7b, 0x3, 0xfa, 0xe6, 0xe0, 0x8b, 0x7f, 0x51, 0xb1, 0x56, 0x17, 0xed, 0x26, 0xe4, 0xa4, 0x1e, 0x4, 0x9d, 0x6f, 0xd3, 0x38, 0xcf, 0x6, 0x3e, 0x5a, 0xde, 0xaf, 0xaf, 0xaf, 0x3, 0x40, 0xfe, 0x8, 0xc7, 0x3c, 0x37, 0x16, 0x34, 0xee, 0x98, 0x6e, 0x20, 0x1c, 0x3f, 0xb0, 0x68, 0x41, 0xa2, 0x31, 0x5, 0x61, 0x1f, 0x45, 0x20, 0x4d, 0x2f, 0x40, 0xa7, 0xe5, 0x10, 0x17, 0x65, 0xd5, 0xcd, 0xbd, 0x63, 0x99, 0x9e, 0x34, 0x7f, 0x43, 0x43, 0xc8, 0xba, 0x97, 0x3, 0x7c, 0x7a, 0xf0, 0x25, 0xf7, 0xfd, 0xf7, 0xe0, 0xa9, 0xf, 0xec, 0xdd, 0xe6, 0x32, 0xc5, 0xbd, 0x18, 0x3c, 0xf5, 0x57, 0xdd, 0x1, 0xf6, 0x85, 0xec, 0x41, 0x20, 0x7a, 0x43, 0x38, 0x4, 0xd0, 0x27, 0x25, 0x7b, 0x24, 0x81, 0x81, 0xf0, 0xe7, 0xa, 0x80, 0xf0, 0x36, 0xaf, 0x35, 0x51, 0xcf, 0x3f, 0xf, 0x32, 0xf5, 0x75, 0xe3, 0xa4, 0x6f, 0x5c, 0x75, 0xf3, 0xbf, 0xb6, 0xf9, 0x4, 0xae, 0xdd, 0x5, 0x86, 0x5c, 0xfa, 0xc0, 0x30, 0x9b, 0x6d, 0xf9, 0xd, 0x80, 0xbd, 0x93, 0x30, 0x2, 0x85, 0xf6, 0xc7, 0x9, 0x6f, 0xba, 0xb9, 0x85, 0x34, 0x2b, 0x5, 0x3e, 0x44, 0x63, 0xee, 0x5c, 0x7d, 0xeb, 0x59, 0x25, 0xf, 0x9f, 0x6a, 0x73, 0x29, 0x86, 0x5d, 0xfe, 0x70, 0xf, 0x6b, 0xdd, 0x7d, 0x65, 0xed, 0x1, 0x34, 0x66, 0x7f, 0x59, 0xdb, 0xb, 0x72, 0xaf, 0x96, 0x6c, 0xff, 0xd6, 0x66, 0xcd, 0x1a, 0x2a, 0x44, 0xbe, 0xe9, 0x38, 0xd, 0x13, 0x56, 0xdd, 0x32, 0xf6, 0x85, 0x24, 0xd2, 0xac, 0x27, 0x18, 0x3c, 0xf5, 0x57, 0x23, 0xe5, 0x66, 0x5e, 0xf4, 0x77, 0x15, 0x49, 0x62, 0x15, 0x7d, 0xab, 0xa3, 0x66, 0x82, 0xd3, 0xc7, 0x4, 0x6c, 0x26, 0xcd, 0xb, 0x34, 0xce, 0x42, 0xc7, 0x98, 0xfb, 0x56, 0xde, 0x3c, 0x36, 0x72, 0x99, 0x78, 0x9b, 0x3d, 0x82, 0x56, 0xce, 0x3d, 0x63, 0x2b, 0xbc, 0x7d, 0x74, 0x5e, 0xb, 0x55, 0x68, 0x20, 0x2d, 0xfa, 0x79, 0x25, 0x49, 0x64, 0xd3, 0x2c, 0x1, 0xe8, 0x63, 0xa5, 0x83, 0x6a, 0xc5, 0x4c, 0xbd, 0xc1, 0xd0, 0xcb, 0x16, 0xef, 0x67, 0x6d, 0x76, 0x9c, 0x3f, 0xcc, 0x55, 0x61, 0x62, 0x8f, 0xd4, 0xc6, 0xb, 0xf4, 0xe8, 0xd0, 0xbe, 0x8c, 0x22, 0xb0, 0x2f, 0xa0, 0x33, 0x61, 0xdd, 0xc1, 0x2e, 0x30, 0x74, 0xf0, 0xd4, 0x7, 0x17, 0xac, 0xbe, 0x75, 0xec, 0xba, 0xe2, 0x4, 0xaa, 0x6e, 0xb9, 0xc3, 0xa6, 0x3f, 0x96, 0x32, 0x34, 0xbf, 0xf7, 0x48, 0xef, 0x2f, 0x45, 0xaa, 0x68, 0xf6, 0x37, 0x34, 0xce, 0xf9, 0xaa, 0x65, 0xde, 0xb1, 0x44, 0x9f, 0x19, 0x7a, 0xd9, 0x83, 0xfb, 0x77, 0x14, 0x71, 0x3a, 0x6, 0x34, 0x0, 0xd6, 0x9d, 0xee, 0xf, 0x94, 0x2c, 0xa8, 0x7b, 0x9b, 0xfc, 0x44, 0x59, 0x6, 0x87, 0x41, 0xfb, 0xcb, 0x9d, 0x5b, 0x24, 0x6f, 0x22, 0x4f, 0x9f, 0x80, 0xec, 0x38, 0x52, 0x7d, 0xa2, 0x4a, 0x55, 0x35, 0x3, 0xac, 0x9c, 0xf3, 0xf9, 0xac, 0x80, 0x17, 0xe0, 0x9f, 0xa3, 0x5a, 0x9d, 0xdc, 0x9f, 0x2f, 0xb7, 0xa7, 0x6d, 0x4, 0x9a, 0x86, 0xbd, 0x40, 0xc2, 0x88, 0xce, 0x26, 0x59, 0x92, 0x20, 0xd9, 0x43, 0x1, 0xec, 0x7, 0x50, 0x85, 0xcb, 0x3b, 0xc2, 0x78, 0xa8, 0x1c, 0x87, 0x28, 0xfe, 0xb6, 0x50, 0xbb, 0xa0, 0xdf, 0xad, 0xbe, 0x4a, 0xe3, 0x6c, 0x8c, 0x2a, 0x57, 0x4d, 0x63, 0xf7, 0x1f, 0x6e, 0x19, 0xfb, 0x2a, 0x8d, 0x79, 0x33, 0x98, 0x32, 0x8e, 0x76, 0x74, 0x8d, 0x9a, 0xf4, 0x88, 0xb3, 0x6d, 0x53, 0x0, 0x5, 0xe9, 0xe3, 0xb2, 0xf6, 0xe4, 0x21, 0x97, 0x2d, 0xee, 0xd9, 0xb9, 0x64, 0x4b, 0x6, 0x6, 0x5f, 0xfa, 0xe0, 0x60, 0x59, 0x4d, 0xf6, 0x55, 0xdd, 0xdc, 0x36, 0x37, 0x49, 0x40, 0xac, 0xd7, 0x40, 0xce, 0x96, 0xf, 0x10, 0xdc, 0xd2, 0xd0, 0xfd, 0x63, 0xaf, 0x47, 0xc5, 0xab, 0x89, 0x1, 0x6, 0x5f, 0x72, 0x9f, 0x1, 0xcc, 0x3, 0x2, 0x32, 0x2, 0x90, 0x53, 0xe5, 0xa, 0x2e, 0x14, 0x75, 0x61, 0xc5, 0x5d, 0x5f, 0x41, 0x78, 0x9e, 0x71, 0xa1, 0xf1, 0xb2, 0xf6, 0xd4, 0xc4, 0xa9, 0xd1, 0x9, 0x40, 0xe0, 0xc, 0xc0, 0x8e, 0xf1, 0x1c, 0xab, 0x0, 0x76, 0xc0, 0x89, 0x68, 0x34, 0x39, 0x5f, 0x3e, 0x90, 0x66, 0x57, 0xf1, 0x9, 0xa6, 0x1, 0xd4, 0xc4, 0x0, 0xd, 0x3d, 0x7a, 0xb, 0x34, 0xf7, 0x4a, 0xc8, 0xfa, 0x54, 0x8c, 0x98, 0x19, 0x2a, 0x35, 0x25, 0x5c, 0x1c, 0xb7, 0x60, 0x37, 0xb0, 0x83, 0x49, 0x9d, 0x3d, 0xe4, 0xd2, 0x87, 0x7a, 0x77, 0x36, 0x1, 0x6b, 0x81, 0x21, 0x97, 0x3e, 0x74, 0x2, 0x64, 0xc7, 0xe6, 0x25, 0xff, 0xf0, 0xa, 0xea, 0xb6, 0xe0, 0xaa, 0x54, 0x58, 0xdc, 0xb7, 0x61, 0x13, 0x2d, 0x77, 0xd1, 0x98, 0x57, 0xe2, 0xca, 0x57, 0x13, 0x3, 0x2c, 0xfb, 0xe9, 0xb1, 0xa2, 0x71, 0x56, 0x80, 0x39, 0x37, 0x2e, 0x86, 0x57, 0xf8, 0xb4, 0x86, 0x52, 0x52, 0x8e, 0xf7, 0x3e, 0xef, 0x2e, 0x45, 0x48, 0x1a, 0x7, 0xe0, 0x92, 0x76, 0xa0, 0x4b, 0x87, 0xc0, 0xb0, 0x69, 0x8f, 0xf4, 0x4, 0xf4, 0x45, 0x49, 0x47, 0x7b, 0x92, 0xbf, 0x9, 0x26, 0x4f, 0x22, 0xf0, 0x11, 0x87, 0xab, 0x52, 0x61, 0xb1, 0xd, 0xcb, 0x77, 0x15, 0x20, 0x40, 0x2e, 0x91, 0x70, 0x7f, 0x5c, 0x19, 0x6b, 0xd6, 0xdf, 0x57, 0xcd, 0x3d, 0x7d, 0xab, 0x31, 0xce, 0x8b, 0x20, 0x4b, 0xc, 0x3, 0x95, 0x76, 0x5f, 0x26, 0x30, 0x3e, 0x76, 0x87, 0xec, 0x85, 0x43, 0x2e, 0x7d, 0x68, 0x6c, 0x47, 0x10, 0x2c, 0x69, 0x90, 0xb5, 0x57, 0x49, 0xf6, 0xdc, 0xd0, 0xce, 0x1d, 0x55, 0xe2, 0x4, 0x95, 0xc6, 0xb, 0xe5, 0x65, 0x56, 0xff, 0xe1, 0x96, 0x33, 0x63, 0xd7, 0x59, 0x24, 0x62, 0xc0, 0x31, 0x4e, 0xea, 0x1a, 0x0, 0x9b, 0xdb, 0xd2, 0xc9, 0xc7, 0x89, 0x7f, 0x45, 0xcf, 0x7e, 0x55, 0x68, 0x25, 0xdb, 0x1f, 0xd0, 0x15, 0xc3, 0xa7, 0x3f, 0xba, 0x17, 0x76, 0x23, 0x18, 0x7a, 0xf9, 0xc3, 0x17, 0xc9, 0xba, 0x97, 0x90, 0xec, 0xe6, 0x1f, 0x22, 0xdb, 0xca, 0x15, 0x24, 0xa, 0x3f, 0xa5, 0xde, 0xb0, 0x8d, 0xf1, 0x82, 0x85, 0x96, 0xfe, 0x53, 0xc9, 0x35, 0x16, 0xc9, 0x30, 0x80, 0x49, 0xfd, 0x15, 0x60, 0x16, 0x2c, 0xa7, 0xb4, 0xb4, 0x56, 0x78, 0xe2, 0x9e, 0x7d, 0x7f, 0x44, 0x43, 0x1a, 0x40, 0xfa, 0xbc, 0xeb, 0x66, 0xef, 0x4e, 0x88, 0x36, 0xed, 0xe, 0xc3, 0xa6, 0x3d, 0x72, 0x34, 0x64, 0xaf, 0x4, 0xd1, 0x97, 0x9e, 0xda, 0xc7, 0xb0, 0x7a, 0x86, 0x12, 0xf8, 0x29, 0x3b, 0x61, 0x56, 0x3e, 0x9e, 0x48, 0xe3, 0xef, 0x4b, 0x65, 0x5e, 0x26, 0xcd, 0xba, 0x52, 0x65, 0xad, 0x99, 0x1, 0x86, 0x5f, 0xf1, 0x44, 0xca, 0x75, 0x33, 0x17, 0x93, 0xdc, 0xb3, 0x60, 0x82, 0xa3, 0xc6, 0x8b, 0x86, 0x14, 0x4, 0x1a, 0x7a, 0x9b, 0x2b, 0xc9, 0x9e, 0x36, 0xf4, 0xf2, 0xc5, 0x8b, 0x3b, 0x9b, 0xb8, 0xe5, 0x60, 0xd8, 0xb4, 0x47, 0x87, 0x59, 0xd7, 0x9d, 0x2b, 0xd9, 0x91, 0xb9, 0x63, 0x71, 0x88, 0xa, 0x8d, 0x64, 0x85, 0x97, 0x2, 0xa5, 0x2e, 0x3e, 0x9d, 0x70, 0x78, 0x4e, 0x93, 0x22, 0x9d, 0x7b, 0xff, 0x70, 0xf3, 0xbf, 0xfe, 0xb2, 0x54, 0x79, 0x6b, 0x62, 0x80, 0x61, 0x57, 0x3c, 0x9e, 0x92, 0xcd, 0x5c, 0x27, 0xeb, 0xde, 0x0, 0xa0, 0x67, 0xc1, 0x92, 0xe4, 0x4, 0x2e, 0x7f, 0xdf, 0x3b, 0xfa, 0x27, 0x8c, 0xc1, 0xba, 0xf6, 0xb3, 0x43, 0x2e, 0x5b, 0x7c, 0x7f, 0x65, 0xa5, 0xec, 0x38, 0x18, 0x7a, 0xf9, 0xa3, 0x43, 0x25, 0xf7, 0x2e, 0x40, 0x47, 0xfa, 0x36, 0xd, 0x86, 0x7e, 0x6b, 0xc1, 0x3, 0xbd, 0x65, 0xfe, 0x8, 0x7e, 0xc3, 0x57, 0xee, 0x14, 0x94, 0xf0, 0x5, 0xc0, 0xa5, 0xe1, 0xdf, 0xca, 0x95, 0xb9, 0x6a, 0x6, 0x18, 0x7a, 0xf9, 0xa3, 0xd, 0x72, 0x33, 0xdf, 0xb3, 0xae, 0xfb, 0xdf, 0x0, 0xd3, 0x5e, 0x68, 0xb4, 0x64, 0x5f, 0x9d, 0x2a, 0xd3, 0x3a, 0xdc, 0x18, 0xa6, 0x21, 0x9d, 0x39, 0xe4, 0xd2, 0x87, 0x7e, 0x3b, 0xf4, 0xf2, 0x47, 0x92, 0xde, 0x95, 0xac, 0x26, 0x18, 0x36, 0xed, 0xb1, 0x93, 0xad, 0xcd, 0x3c, 0x28, 0xab, 0xc3, 0xa, 0xd7, 0x52, 0x94, 0xd2, 0x7a, 0xe2, 0x70, 0x81, 0xd6, 0x71, 0xf3, 0x9a, 0xdd, 0x2e, 0x92, 0x1b, 0x40, 0xf3, 0xa6, 0x84, 0x5d, 0xa, 0xb6, 0x53, 0x4, 0x43, 0x62, 0x86, 0x27, 0xfc, 0x9, 0x6c, 0x75, 0x68, 0x67, 0x31, 0x54, 0xc5, 0x0, 0xc3, 0xaf, 0x78, 0xbc, 0x1b, 0xa0, 0x1f, 0x59, 0x6b, 0xaf, 0x3, 0xe1, 0xd0, 0x10, 0xc1, 0x21, 0xc7, 0x85, 0x2b, 0xc7, 0xa2, 0x18, 0x9f, 0x45, 0xe1, 0xcc, 0x8b, 0x2b, 0x5, 0x78, 0x8, 0xb8, 0x9f, 0xa1, 0x74, 0x9, 0x10, 0x46, 0xd0, 0xd1, 0xd6, 0xba, 0x2f, 0xf, 0xb9, 0xfc, 0x91, 0xe3, 0x3a, 0x8c, 0xc2, 0x25, 0x60, 0xc8, 0x65, 0xf, 0xff, 0xa7, 0xb5, 0xd9, 0x45, 0x24, 0xf, 0xa, 0xd4, 0x6f, 0x1a, 0xe3, 0xf9, 0x39, 0x17, 0x8a, 0x3f, 0x85, 0xf5, 0x46, 0xc, 0x2e, 0xa, 0xf1, 0x26, 0x3f, 0x2e, 0x7d, 0x7c, 0xac, 0x5c, 0x75, 0xf3, 0x99, 0x3, 0x8d, 0x93, 0xfe, 0x94, 0x49, 0x35, 0xee, 0x63, 0x52, 0x4d, 0x4d, 0x26, 0x95, 0xee, 0x63, 0x9c, 0xf4, 0x20, 0x3a, 0xe9, 0xd1, 0x74, 0xd2, 0x67, 0xd1, 0x38, 0x5f, 0xa6, 0x71, 0xbe, 0x44, 0xf0, 0xd9, 0x72, 0x65, 0x2f, 0x27, 0xb8, 0x47, 0x10, 0xff, 0xd7, 0x7b, 0xca, 0xda, 0xaf, 0x4a, 0xf6, 0x3b, 0x8, 0x56, 0xa3, 0xb0, 0xd2, 0x95, 0xae, 0x55, 0x2d, 0x8c, 0xf5, 0xd8, 0x5b, 0x62, 0xc8, 0xb9, 0x70, 0x2b, 0x68, 0x1e, 0x4b, 0x77, 0xdb, 0xe7, 0xbc, 0x17, 0x67, 0x1c, 0xd3, 0xe1, 0x9b, 0x48, 0xe, 0xbf, 0xe2, 0x89, 0x46, 0xeb, 0x66, 0xd6, 0xca, 0xba, 0x7, 0x91, 0xdc, 0x23, 0x98, 0x92, 0x87, 0xc4, 0x44, 0x71, 0x12, 0x78, 0xe8, 0x92, 0xab, 0x40, 0xe7, 0xe4, 0x95, 0x73, 0x3e, 0xf7, 0x7e, 0x71, 0x94, 0xa3, 0xbe, 0xf2, 0x5b, 0xb6, 0x6c, 0x7b, 0x97, 0x4e, 0xba, 0x81, 0xb2, 0xd6, 0x48, 0xd6, 0x5d, 0x35, 0xf7, 0x8c, 0xb2, 0x47, 0xcc, 0x54, 0x44, 0x85, 0xa1, 0xd3, 0x1e, 0xed, 0xe, 0x60, 0x32, 0xac, 0x9d, 0x5, 0xf8, 0x67, 0xff, 0xa1, 0xe3, 0xf, 0x8c, 0x40, 0xe1, 0x3c, 0x78, 0xb, 0xc8, 0xb7, 0x4, 0xde, 0xea, 0x66, 0xb3, 0xd7, 0xaf, 0xb9, 0xf5, 0xcc, 0x4c, 0xd, 0x59, 0xb4, 0x9, 0x86, 0x5c, 0xfe, 0x48, 0x9a, 0xc0, 0x22, 0x12, 0x47, 0xc9, 0xda, 0xdc, 0x2c, 0x1b, 0x2b, 0x26, 0x7a, 0x25, 0x55, 0x46, 0x56, 0xe0, 0x5d, 0xab, 0xe6, 0x9e, 0x3e, 0x25, 0xc9, 0xba, 0x54, 0x54, 0xd8, 0x61, 0xd3, 0x1e, 0x3b, 0x49, 0x72, 0x7f, 0xe3, 0x89, 0xb5, 0x1e, 0x9b, 0xb7, 0x4a, 0x2d, 0xee, 0xec, 0x87, 0x70, 0xcc, 0xb8, 0xc5, 0x23, 0x2c, 0x8a, 0xab, 0xc8, 0x38, 0x91, 0xa7, 0x83, 0x49, 0xda, 0x4a, 0x9a, 0xd7, 0x40, 0x2e, 0x2, 0xcc, 0x4f, 0x56, 0xce, 0xf9, 0x6c, 0xe2, 0x1e, 0x45, 0xc3, 0xaf, 0x78, 0x7c, 0xa8, 0xb5, 0xee, 0xb5, 0xde, 0xde, 0x48, 0x3a, 0x88, 0xa4, 0xbf, 0x3f, 0x62, 0x20, 0xaa, 0x7b, 0xc7, 0x27, 0xb6, 0xaa, 0x53, 0xb8, 0x2e, 0x51, 0x38, 0x2a, 0xf6, 0xa4, 0x2e, 0xc4, 0x97, 0xbf, 0xf, 0x3, 0x9f, 0x4d, 0x35, 0x34, 0x7d, 0x6e, 0xd9, 0xcf, 0x4e, 0x4a, 0xf4, 0xc8, 0x98, 0x8a, 0xe, 0x8d, 0x12, 0xf0, 0x16, 0xc0, 0x55, 0x20, 0x86, 0x12, 0x85, 0x47, 0xb7, 0x14, 0x54, 0xa8, 0x18, 0xca, 0x59, 0x7f, 0xc2, 0x61, 0x2c, 0xfb, 0x5d, 0x1e, 0xb5, 0xb9, 0x19, 0x70, 0x89, 0x64, 0xf, 0xc9, 0xe, 0x84, 0x78, 0x10, 0xa9, 0xb, 0x87, 0x4e, 0x7b, 0x74, 0x29, 0xc0, 0xc5, 0x0, 0x9f, 0x58, 0x75, 0xd3, 0xe7, 0x3e, 0xac, 0x16, 0x41, 0x43, 0xa7, 0x3d, 0x76, 0x24, 0x81, 0x33, 0x41, 0x9c, 0x62, 0xdd, 0xec, 0x27, 0x1, 0xf4, 0x26, 0xd1, 0xe4, 0x17, 0x26, 0xe7, 0xa, 0x17, 0xb9, 0x8c, 0x92, 0x6d, 0xb8, 0x8f, 0x7f, 0xe, 0xed, 0xba, 0xc2, 0xd7, 0x68, 0xcc, 0x6d, 0x49, 0x13, 0x3f, 0x8e, 0x14, 0x25, 0x61, 0xd8, 0xf4, 0x5f, 0x9f, 0x2e, 0xeb, 0x3e, 0xc, 0x44, 0xad, 0x70, 0xed, 0x70, 0x28, 0x68, 0x57, 0xa1, 0x1d, 0x4b, 0x20, 0xa9, 0x19, 0xe4, 0x3f, 0x0, 0xbc, 0xb, 0xe0, 0x6d, 0x80, 0x7f, 0x34, 0xc6, 0xbc, 0x28, 0x61, 0x83, 0x64, 0x37, 0x1b, 0x63, 0xb6, 0x9, 0xcc, 0x2, 0x70, 0x8d, 0x31, 0x8e, 0x9b, 0xcd, 0x34, 0x2, 0xec, 0x66, 0xc, 0xf, 0x4, 0x74, 0x8c, 0xb5, 0x3a, 0xe, 0xd0, 0x1, 0x0, 0x7a, 0xc8, 0xda, 0xde, 0x24, 0xf7, 0xcb, 0x21, 0x2d, 0x7c, 0x42, 0xa, 0xa, 0xfb, 0xe9, 0x44, 0x2a, 0x15, 0x4a, 0x4f, 0x92, 0x5, 0xcd, 0x8d, 0x3d, 0xf7, 0xeb, 0x73, 0xd5, 0x33, 0xd7, 0xf, 0x4e, 0x5c, 0xce, 0xa9, 0xf8, 0xec, 0x60, 0x9, 0x2b, 0x40, 0xf3, 0x2, 0xa0, 0xe3, 0x2, 0x4f, 0x9e, 0xf0, 0x69, 0xd1, 0xed, 0xf, 0x5, 0x63, 0x49, 0xee, 0xc1, 0x3b, 0x69, 0x3b, 0x68, 0x3a, 0x10, 0xd, 0x1b, 0x25, 0x1c, 0x2, 0xe0, 0x10, 0x3f, 0xc6, 0x9, 0x92, 0x1d, 0x27, 0xe1, 0x7d, 0x48, 0xcd, 0x90, 0xcd, 0x10, 0xb4, 0x0, 0xe4, 0x66, 0xb2, 0x24, 0xe9, 0x0, 0x4a, 0x59, 0xab, 0xee, 0x80, 0xf6, 0x7, 0x90, 0xf3, 0x48, 0xa, 0x16, 0xc9, 0xf8, 0xe, 0xd1, 0x2c, 0x76, 0xe7, 0xab, 0x9c, 0xf8, 0xc5, 0xe3, 0x40, 0x1, 0x7e, 0x45, 0x43, 0x4a, 0xb0, 0x0, 0xc, 0x69, 0x9e, 0x14, 0xf9, 0x83, 0xf6, 0x20, 0x3e, 0x50, 0x5, 0x3, 0x90, 0x7c, 0x17, 0xe4, 0x77, 0x64, 0xdd, 0x27, 0xdb, 0xeb, 0xb8, 0xb4, 0xa, 0x4a, 0x13, 0x2a, 0x57, 0x48, 0x81, 0x24, 0xc2, 0x4e, 0x97, 0xc1, 0x88, 0xda, 0x1d, 0x40, 0x5f, 0x40, 0x7d, 0xc1, 0x9c, 0x4a, 0x91, 0x4b, 0x26, 0x70, 0x79, 0xf, 0x8c, 0x6e, 0xc8, 0x7f, 0x9b, 0xcb, 0x28, 0xbf, 0x59, 0x46, 0xb2, 0x65, 0x2f, 0xc4, 0x6f, 0xee, 0x5c, 0x24, 0x43, 0x72, 0x9, 0x8d, 0xf3, 0x5f, 0x2b, 0x67, 0x9f, 0x5a, 0xd6, 0xa0, 0x53, 0x2d, 0x54, 0xdc, 0x85, 0xaf, 0x9c, 0xf3, 0x59, 0x57, 0x56, 0xcf, 0x1, 0xe6, 0x7, 0xcc, 0x4f, 0x3b, 0x29, 0xce, 0xae, 0xf, 0xc4, 0xdb, 0xb2, 0x11, 0x11, 0x16, 0xf5, 0x1e, 0x31, 0xdf, 0x44, 0x7d, 0xe7, 0x3f, 0x33, 0x58, 0x72, 0xe, 0x7f, 0x5b, 0x4e, 0x7f, 0x7e, 0x1, 0x86, 0x6, 0x86, 0x26, 0xbf, 0xb6, 0xda, 0xf, 0xf3, 0xe6, 0x1c, 0x20, 0xd2, 0x0, 0xfe, 0x7d, 0xb1, 0x52, 0x5e, 0x6c, 0xcf, 0x47, 0x4c, 0x19, 0x4b, 0xc5, 0x61, 0x89, 0xfa, 0x86, 0x5d, 0xb9, 0xe8, 0x19, 0x73, 0x1e, 0x58, 0x31, 0xfb, 0xd4, 0x76, 0xf5, 0x8e, 0xae, 0x6a, 0xc, 0x5f, 0x75, 0xd3, 0xe7, 0x32, 0xc6, 0x71, 0x66, 0xd0, 0x98, 0x3f, 0x7a, 0x1e, 0x81, 0xf0, 0x14, 0x83, 0xbc, 0xcd, 0x1a, 0xa0, 0x77, 0x94, 0x27, 0x3, 0x79, 0x3d, 0xf8, 0xf1, 0xc3, 0xe4, 0x1b, 0x11, 0x7c, 0xbb, 0x49, 0x7e, 0x4d, 0x8, 0xb, 0xc3, 0xa, 0xec, 0x61, 0x21, 0x3b, 0x49, 0x2e, 0x6e, 0x48, 0x78, 0x6c, 0x65, 0x53, 0x2a, 0x8e, 0x1b, 0x32, 0x52, 0x79, 0xc6, 0x2b, 0x22, 0xbc, 0xcd, 0xa1, 0x77, 0xa, 0x8b, 0x1f, 0x25, 0x7c, 0x5f, 0x9c, 0x6f, 0x51, 0x18, 0x23, 0xca, 0x15, 0x67, 0xe3, 0x29, 0x28, 0x77, 0x44, 0x1d, 0xa, 0x3b, 0x6, 0x56, 0xdc, 0x43, 0x77, 0x8, 0x3, 0x0, 0xc0, 0x8a, 0xd9, 0xa7, 0xbc, 0x9, 0x98, 0x6f, 0x48, 0xb0, 0xc1, 0x4a, 0x97, 0x90, 0xcd, 0x3a, 0xa8, 0x72, 0x40, 0x71, 0xff, 0x40, 0x54, 0x13, 0xd8, 0xaa, 0x3d, 0xd3, 0x5e, 0xb0, 0xb5, 0x1d, 0x22, 0x30, 0x57, 0x80, 0xc5, 0x8, 0xec, 0xc6, 0xc5, 0x47, 0x1b, 0xe2, 0x17, 0x7f, 0xc7, 0x32, 0xf9, 0x97, 0xcb, 0xaf, 0x5c, 0x1e, 0x95, 0x94, 0xc5, 0xbb, 0xf7, 0x27, 0xc0, 0x34, 0x61, 0xd8, 0x15, 0x4f, 0x8c, 0xa9, 0x4b, 0x6, 0x0, 0x80, 0x15, 0x37, 0x9e, 0xf2, 0x2b, 0x81, 0x73, 0xfd, 0x59, 0x89, 0xe0, 0xbc, 0xdb, 0x9c, 0xdf, 0xa3, 0x1f, 0x6, 0x1, 0xaf, 0xd0, 0x38, 0xf3, 0x40, 0xf3, 0x3d, 0x90, 0x8f, 0xa3, 0x50, 0x4b, 0x66, 0x72, 0x3e, 0x92, 0x9d, 0x24, 0x8a, 0x24, 0x8, 0x61, 0x1c, 0x2, 0x1a, 0xe, 0x60, 0xca, 0x51, 0x57, 0x3d, 0x9d, 0x6e, 0xaf, 0xfc, 0x6a, 0x56, 0xe3, 0x68, 0x9c, 0xaf, 0xd2, 0x38, 0xbf, 0x1, 0xe8, 0x2, 0xc, 0x66, 0xa5, 0x8, 0xf0, 0x3, 0x81, 0x4f, 0x1, 0x9c, 0x4d, 0x9a, 0xff, 0x30, 0xc6, 0x4c, 0x5f, 0x31, 0xfb, 0x94, 0x6f, 0x3, 0xe6, 0x6b, 0xa0, 0xf9, 0x6d, 0x28, 0xae, 0xef, 0x27, 0x17, 0xb5, 0x6d, 0x5a, 0xa5, 0x17, 0x6a, 0xfc, 0xbe, 0xf3, 0x2f, 0x7f, 0xd2, 0x43, 0x79, 0xbc, 0x68, 0x8c, 0x9b, 0x75, 0xcf, 0x6b, 0x2f, 0x6, 0x48, 0xa4, 0xc9, 0x8c, 0xb8, 0xf2, 0xa9, 0x23, 0x24, 0xfb, 0x6b, 0x49, 0x69, 0x49, 0x1b, 0xc, 0xb9, 0x95, 0xc6, 0xac, 0x0, 0x78, 0xf3, 0xf2, 0x59, 0x27, 0xbd, 0x19, 0x11, 0xff, 0x13, 0xd6, 0xba, 0xf3, 0x25, 0x9d, 0x60, 0x72, 0xaa, 0x5b, 0xe8, 0xa0, 0xe4, 0x92, 0xc5, 0x6d, 0x4b, 0x6f, 0xd1, 0xd6, 0x78, 0x51, 0x71, 0xc3, 0xcf, 0x95, 0xa4, 0x53, 0xd, 0x4, 0x55, 0x8d, 0xcd, 0x43, 0x5e, 0x2f, 0xca, 0x47, 0x68, 0xcc, 0xf8, 0x95, 0xb3, 0x4f, 0x2e, 0x77, 0xa, 0x7a, 0xd5, 0x25, 0xa8, 0x19, 0x46, 0x5c, 0xf9, 0xd4, 0xf5, 0x92, 0x5e, 0x7, 0x39, 0x6f, 0xc5, 0xac, 0x93, 0xca, 0x6e, 0xf5, 0x3a, 0xfc, 0x4b, 0x4f, 0x35, 0x42, 0xf6, 0x69, 0x41, 0xc7, 0x78, 0x2, 0x1e, 0x73, 0x15, 0x66, 0x58, 0xa7, 0x8b, 0x41, 0x51, 0x78, 0xc, 0x29, 0x45, 0x22, 0x96, 0xf9, 0xbe, 0x38, 0x4e, 0x71, 0xfc, 0x28, 0x4, 0x29, 0x26, 0x8d, 0xf6, 0x60, 0x15, 0x7f, 0x78, 0x7c, 0x97, 0x34, 0x3f, 0x58, 0x31, 0xfb, 0xe4, 0x1f, 0x26, 0x9d, 0x7e, 0xa7, 0xe, 0x9a, 0x23, 0xaf, 0x59, 0x4a, 0xb7, 0x65, 0xfb, 0xe3, 0x24, 0x8e, 0x6, 0xd0, 0xc3, 0xdb, 0x3c, 0x23, 0xd8, 0x87, 0x24, 0x8a, 0x5, 0x18, 0xf1, 0x5c, 0xe9, 0xe4, 0x43, 0x5c, 0xba, 0xa5, 0x58, 0x24, 0xa, 0x65, 0xc5, 0xdf, 0x95, 0xcb, 0x2f, 0xae, 0x4c, 0x8c, 0xf9, 0x46, 0xc1, 0x7a, 0x4b, 0xff, 0xe0, 0x68, 0x3e, 0x63, 0x85, 0xcf, 0xaf, 0xba, 0xf1, 0x94, 0x44, 0xcd, 0xc1, 0x9d, 0x6a, 0xca, 0x5d, 0xf6, 0xd3, 0x63, 0xb5, 0xf2, 0xc6, 0x53, 0x4f, 0x25, 0x53, 0xb7, 0x4a, 0x7c, 0xc3, 0x57, 0xd5, 0x19, 0xbd, 0xce, 0x90, 0x31, 0xcf, 0x61, 0x4d, 0xa1, 0x54, 0xdc, 0x8, 0xbd, 0x32, 0x36, 0x9d, 0xb8, 0x30, 0x96, 0xf8, 0xae, 0x5c, 0x7e, 0x71, 0x71, 0xe2, 0xbe, 0xf1, 0xe4, 0xe3, 0x90, 0x6e, 0x3b, 0x84, 0xe4, 0xb7, 0x92, 0xa6, 0x41, 0x67, 0xdb, 0xf2, 0x1, 0x0, 0xcb, 0x67, 0x8d, 0xb9, 0x16, 0x34, 0xd7, 0x4a, 0x58, 0xf, 0xef, 0x4, 0x92, 0x28, 0x4a, 0xed, 0x56, 0x57, 0xb0, 0xb7, 0x72, 0xb9, 0xb0, 0x52, 0xdf, 0x6, 0x2e, 0x71, 0x7e, 0xf8, 0x36, 0x0, 0x1f, 0x24, 0x8d, 0xfb, 0xba, 0xd2, 0x9b, 0x86, 0x7f, 0xe9, 0xe9, 0xde, 0xa0, 0x1e, 0x25, 0x30, 0x24, 0x5f, 0xbc, 0xb8, 0x3d, 0x74, 0x6b, 0x19, 0x71, 0x4b, 0xa5, 0xd1, 0x16, 0xa9, 0x22, 0x4e, 0x7a, 0xc8, 0x7d, 0x17, 0xac, 0x95, 0xf4, 0x67, 0x2d, 0x73, 0x5d, 0x9b, 0xef, 0xc9, 0x62, 0x5b, 0x4f, 0xa5, 0x7, 0xdd, 0xbe, 0xb7, 0x4b, 0x46, 0xfe, 0x5b, 0x0, 0x92, 0x5e, 0x27, 0xf9, 0xff, 0x56, 0xcc, 0x3e, 0x69, 0x66, 0xd2, 0x38, 0x6f, 0x77, 0x4b, 0x53, 0x25, 0x60, 0xc, 0xcf, 0x12, 0xb0, 0x7f, 0xa1, 0x46, 0x10, 0xc7, 0xa3, 0x49, 0xf0, 0x6e, 0xb5, 0x69, 0xb3, 0xd5, 0x73, 0x89, 0x19, 0x41, 0x17, 0x40, 0xd6, 0x6f, 0xdc, 0x8d, 0x3e, 0x81, 0x63, 0x36, 0x88, 0x28, 0xdc, 0x37, 0xc0, 0x8f, 0xf3, 0xf, 0xc7, 0x38, 0xd7, 0x2f, 0xfb, 0xd9, 0x89, 0xb3, 0xd1, 0xe, 0x50, 0x17, 0x43, 0x40, 0x0, 0x56, 0x9a, 0x2, 0xb0, 0x4f, 0xcc, 0xa0, 0x19, 0x46, 0x54, 0x95, 0x57, 0xf8, 0xfb, 0xa8, 0xb4, 0xa2, 0xde, 0x17, 0x43, 0x41, 0x9a, 0xf2, 0xaf, 0x90, 0x15, 0x34, 0x6c, 0x14, 0x33, 0x24, 0xcd, 0x12, 0x63, 0x9c, 0x13, 0x49, 0x73, 0xa9, 0xf2, 0x7b, 0x39, 0xd2, 0x5b, 0xff, 0x58, 0xd0, 0xe5, 0xe7, 0xbc, 0x87, 0x83, 0xd6, 0xef, 0xf9, 0xf4, 0xf3, 0xb2, 0xf6, 0x22, 0x3e, 0x50, 0x6f, 0x3d, 0x0, 0xb9, 0xb7, 0x7f, 0xab, 0xe8, 0xa6, 0x5f, 0x6b, 0xab, 0x2f, 0x47, 0xe4, 0x36, 0x30, 0x41, 0x99, 0x11, 0x42, 0xc1, 0xc6, 0xf7, 0xc4, 0x12, 0x49, 0xff, 0x43, 0xf2, 0xe9, 0x65, 0x33, 0x47, 0x67, 0x0, 0xfc, 0x6e, 0xe4, 0x55, 0xcf, 0xbe, 0x2d, 0x6b, 0x7f, 0x9, 0x61, 0xcf, 0x12, 0xbe, 0x23, 0x16, 0xa0, 0x1, 0xf9, 0x24, 0xc9, 0x6f, 0x2e, 0x9b, 0x39, 0x7a, 0x59, 0x72, 0x18, 0x6e, 0xd, 0x75, 0xd3, 0x3, 0xc, 0xbf, 0xf2, 0x99, 0x43, 0xad, 0xd4, 0xd8, 0x7a, 0x7d, 0x21, 0x4a, 0x48, 0xe2, 0x40, 0xbc, 0x74, 0x8f, 0x98, 0x6f, 0xa3, 0x24, 0x7d, 0xc4, 0xe4, 0x17, 0x91, 0x6, 0x10, 0x78, 0xfb, 0x22, 0x98, 0xb4, 0xb, 0xc9, 0x76, 0xa4, 0x31, 0xf, 0xd2, 0x38, 0xa3, 0x40, 0xf3, 0x79, 0x3a, 0xd, 0x4f, 0x2c, 0xff, 0xd9, 0x89, 0x39, 0x1f, 0xc5, 0x65, 0x33, 0x47, 0x3f, 0xe, 0x9a, 0xa1, 0x2, 0x7e, 0xed, 0x37, 0x79, 0x81, 0x94, 0x37, 0xc9, 0xc8, 0x60, 0x1, 0x89, 0x1, 0x79, 0x9b, 0x80, 0x69, 0xed, 0x4d, 0x7c, 0xa0, 0x9e, 0x7a, 0x0, 0xa2, 0x1f, 0xc1, 0xc6, 0xdc, 0x53, 0x4e, 0xb2, 0x2a, 0xd7, 0x52, 0x5b, 0x79, 0xd0, 0xf8, 0xdd, 0x27, 0x83, 0x77, 0x88, 0x77, 0x57, 0x60, 0x44, 0x7a, 0xe5, 0x7b, 0x89, 0xfc, 0x9c, 0x7d, 0xe0, 0xe, 0x61, 0xfe, 0xa, 0x70, 0x11, 0xa8, 0x5b, 0x1, 0xbc, 0xe, 0x68, 0xe7, 0xf2, 0x99, 0xa3, 0x23, 0x3d, 0x72, 0x97, 0xff, 0x6c, 0xf4, 0x9f, 0x47, 0x5c, 0xf5, 0xec, 0x64, 0x8, 0x93, 0x24, 0x3b, 0x23, 0xa8, 0x82, 0xef, 0xdc, 0x42, 0x80, 0x5f, 0x3, 0x79, 0xc7, 0x8a, 0x99, 0x27, 0xbc, 0xd7, 0x11, 0x68, 0xaf, 0x1f, 0x6, 0x0, 0x8e, 0x5, 0xd8, 0xc3, 0xf7, 0xc9, 0xa8, 0xc8, 0xc9, 0xc4, 0x9f, 0x7d, 0xa, 0x3c, 0x68, 0x2, 0x46, 0x0, 0x80, 0xd0, 0x92, 0x6c, 0x0, 0x21, 0x71, 0xbd, 0x48, 0x66, 0xab, 0xc6, 0x9b, 0x97, 0x0, 0xb2, 0x20, 0x7, 0x81, 0xdc, 0x22, 0x69, 0xeb, 0xf2, 0x99, 0xa3, 0xdb, 0xe4, 0x88, 0xba, 0x7c, 0xe6, 0xe8, 0x77, 0x46, 0x5e, 0xbd, 0x64, 0x2e, 0xc4, 0xc5, 0x90, 0x9e, 0x5, 0x70, 0xa0, 0xa4, 0x77, 0x40, 0x4e, 0x4, 0xf4, 0xc2, 0xa, 0x6f, 0xc8, 0xe8, 0x10, 0xa8, 0x1b, 0x35, 0x70, 0xf8, 0x97, 0x9f, 0x7d, 0x9e, 0xc4, 0x31, 0xbe, 0x27, 0x47, 0x5b, 0x9, 0x92, 0xd7, 0xbb, 0x3c, 0xcf, 0xd9, 0xdb, 0x1, 0x2c, 0x5, 0x70, 0x32, 0xa0, 0xb3, 0x51, 0x62, 0xdb, 0xd9, 0x90, 0xb7, 0x50, 0x45, 0x6e, 0xed, 0x45, 0xbd, 0x4d, 0x66, 0xf9, 0xcc, 0xd1, 0xd, 0x6d, 0xfa, 0x30, 0x6, 0x46, 0x5e, 0xbd, 0xe4, 0x50, 0x49, 0xc3, 0x0, 0xac, 0x5f, 0x3e, 0xf3, 0x84, 0xd, 0xed, 0x89, 0xe3, 0x48, 0x3c, 0x74, 0x74, 0x86, 0x71, 0x30, 0xe2, 0xaa, 0xe7, 0xde, 0x2, 0xd0, 0x2b, 0xbc, 0xdf, 0x50, 0x29, 0xa2, 0x14, 0xbf, 0x97, 0xf4, 0x17, 0x80, 0x13, 0x1, 0xac, 0xa1, 0x77, 0x9e, 0x71, 0x2f, 0x0, 0x7b, 0x4a, 0x6a, 0x80, 0x77, 0xbc, 0x7d, 0xf, 0x0, 0x9f, 0x2, 0xd4, 0x17, 0xc0, 0xbe, 0x0, 0x3e, 0x9, 0x78, 0x1b, 0x51, 0x55, 0xea, 0xcf, 0x1f, 0xc, 0x33, 0x92, 0x32, 0xa4, 0xe9, 0xb6, 0x7c, 0xe6, 0xf1, 0xd9, 0xb6, 0x7e, 0x1b, 0x5, 0x47, 0x7f, 0x65, 0x69, 0xea, 0xf7, 0x33, 0x8e, 0xad, 0x29, 0x8d, 0x6a, 0xa1, 0x6e, 0x86, 0x0, 0x82, 0x3f, 0x17, 0xf4, 0x15, 0xf9, 0xb, 0xa1, 0x3c, 0xbf, 0x48, 0x8f, 0x28, 0x11, 0x94, 0xf1, 0x37, 0x44, 0xf4, 0x5, 0x32, 0x6f, 0x14, 0xb8, 0xce, 0xcd, 0xba, 0x7f, 0x58, 0x39, 0xfb, 0x44, 0xb, 0x60, 0x93, 0x7f, 0xe5, 0x60, 0xc4, 0xd5, 0x2f, 0x90, 0xb0, 0x3d, 0x0, 0xee, 0x9, 0x8f, 0x21, 0xfa, 0xc8, 0x6a, 0x89, 0x31, 0x74, 0x0, 0x6f, 0x71, 0x65, 0x5, 0x83, 0x8e, 0x7f, 0xca, 0x6d, 0x32, 0xde, 0x81, 0x9d, 0x45, 0x7c, 0xa0, 0x8e, 0x18, 0x40, 0xc0, 0x8f, 0x48, 0xb3, 0x44, 0xb2, 0x97, 0x82, 0x3c, 0x2d, 0x24, 0x4, 0x14, 0xf4, 0xba, 0x7e, 0x80, 0xbf, 0xf, 0x1e, 0x20, 0x6b, 0x9, 0xe0, 0xfb, 0x12, 0x1f, 0xf5, 0x89, 0x1f, 0x9, 0xcb, 0x6f, 0x38, 0x4e, 0x0, 0xb6, 0xf8, 0x17, 0x46, 0x5c, 0xb5, 0xe4, 0x75, 0x92, 0xbf, 0x15, 0x70, 0x1c, 0x80, 0x22, 0x51, 0xa1, 0x75, 0xe1, 0x42, 0x5c, 0xa8, 0xd0, 0x9e, 0x8c, 0xdb, 0xea, 0xa8, 0x13, 0xad, 0xa, 0xea, 0x46, 0xd, 0x5c, 0x3e, 0xf3, 0xf8, 0xd7, 0x97, 0xdd, 0x30, 0xea, 0x3e, 0x80, 0xd7, 0x1, 0xbc, 0x58, 0xc2, 0xaf, 0x3, 0xe7, 0x92, 0x22, 0x87, 0x11, 0x92, 0x46, 0xa1, 0x77, 0xbf, 0x7, 0xf8, 0xbf, 0xcb, 0x67, 0x1e, 0x5f, 0xd1, 0x59, 0x43, 0xc6, 0x18, 0xd2, 0x98, 0xbb, 0x42, 0xf6, 0xf9, 0x78, 0x3b, 0x7d, 0xa1, 0x4b, 0x97, 0x6f, 0xac, 0x81, 0x5, 0xf8, 0x1a, 0xda, 0xd7, 0x61, 0xa0, 0xdd, 0xa1, 0x6e, 0xd9, 0x77, 0xc4, 0x55, 0x4b, 0x8e, 0x4, 0x30, 0x82, 0xe4, 0x89, 0x0, 0xc6, 0x1, 0x8, 0x6f, 0x11, 0x13, 0x8c, 0xc1, 0x9b, 0x1, 0x9c, 0xb5, 0x7c, 0xe6, 0xf1, 0x4b, 0xaa, 0xc9, 0x63, 0xe4, 0xd5, 0x2f, 0x1c, 0x28, 0xd9, 0x4d, 0xfe, 0xb9, 0x88, 0xa5, 0x5c, 0x0, 0xa, 0xc0, 0xd7, 0x30, 0x32, 0x92, 0x16, 0x1, 0x98, 0xbc, 0x7c, 0xe6, 0xf1, 0x65, 0x17, 0x61, 0xd6, 0x2b, 0xd4, 0x2d, 0x3, 0x4, 0x30, 0xe2, 0xea, 0xe7, 0xfb, 0x0, 0x38, 0x3, 0xc0, 0xbf, 0x10, 0x3c, 0xa, 0xc0, 0x18, 0xdf, 0x4a, 0xb0, 0x43, 0xd0, 0x95, 0xcb, 0x6f, 0x18, 0x75, 0x47, 0x8d, 0xe9, 0x3f, 0x65, 0x68, 0x8e, 0x87, 0x77, 0xf6, 0x9e, 0xe7, 0x25, 0x1c, 0xc3, 0xa, 0xb2, 0x5, 0xea, 0xc2, 0x2e, 0x2b, 0xfb, 0x9f, 0x0, 0x7e, 0xb8, 0xfc, 0x86, 0x51, 0x5d, 0xc, 0xd0, 0x11, 0x70, 0xd4, 0x57, 0x96, 0xe, 0x7, 0x30, 0x9, 0x5e, 0x6f, 0xb0, 0xe9, 0xc5, 0x19, 0xc7, 0x7e, 0xb7, 0x96, 0xf4, 0x46, 0x5e, 0xb3, 0x94, 0x92, 0x3d, 0x95, 0xe4, 0xaf, 0x0, 0xec, 0x11, 0xee, 0x5, 0x22, 0xb4, 0x90, 0x9c, 0xfc, 0xe1, 0x3f, 0x5b, 0x0, 0x63, 0x49, 0xf3, 0x48, 0x67, 0x2c, 0x4d, 0x4f, 0xa, 0x76, 0x2b, 0x6, 0x68, 0xf, 0x18, 0x79, 0xcd, 0xd2, 0x3d, 0x24, 0xbd, 0x4c, 0xf2, 0xc0, 0x62, 0xb5, 0x33, 0xce, 0x5b, 0x59, 0xd2, 0x26, 0x92, 0x2f, 0x91, 0xbc, 0xf8, 0xc5, 0x19, 0xc7, 0x6c, 0x6a, 0x4b, 0x3e, 0xf5, 0xa, 0xff, 0xf4, 0xc, 0x0, 0x0, 0x23, 0xaf, 0x7e, 0xe1, 0x7a, 0x1a, 0x5e, 0x7, 0x20, 0xe5, 0xfb, 0x61, 0x65, 0x0, 0xec, 0x82, 0xb0, 0xb, 0xc4, 0xe, 0x0, 0x5b, 0x24, 0x6d, 0x26, 0xb9, 0xd, 0xc2, 0x66, 0x41, 0x4b, 0x8c, 0x31, 0xbf, 0xfb, 0xfd, 0x4f, 0x8e, 0x59, 0x57, 0x63, 0xd6, 0x9d, 0xe, 0x75, 0xa3, 0x6, 0x76, 0x26, 0xd0, 0x98, 0xff, 0x91, 0x74, 0x8, 0x80, 0x1e, 0x24, 0xb7, 0xc0, 0xdb, 0x5b, 0x6f, 0x33, 0xd, 0xdf, 0x3, 0xf0, 0xb6, 0xa4, 0x57, 0x1, 0xbc, 0xf4, 0xe2, 0x8c, 0x63, 0xdf, 0xe9, 0xec, 0xb2, 0x76, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0xd4, 0x6, 0xff, 0x1f, 0x32, 0x68, 0x5, 0x7e, 0x99, 0xd5, 0x97, 0x49, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc3, 0x3e, 0x61, 0xcb, 0x0, 0x0, 0x19, 0xdb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x99, 0x3, 0x94, 0x7b, 0x39, 0x14, 0xc6, 0xd7, 0xb6, 0xed, 0x87, 0x62, 0x6d, 0xdb, 0x33, 0xe5, 0x6b, 0xc7, 0x6b, 0xdb, 0xb6, 0x77, 0x5c, 0xb7, 0x6b, 0xdb, 0xb6, 0x6d, 0xdb, 0xb6, 0xbd, 0xdb, 0x74, 0xbf, 0xde, 0xe6, 0x35, 0xff, 0xe6, 0xcc, 0xdb, 0x1d, 0x9f, 0x37, 0xd3, 0xe4, 0x9c, 0xdf, 0x49, 0x5e, 0x9c, 0x7c, 0x37, 0x37, 0x39, 0xed, 0x54, 0x2a, 0xa8, 0xa0, 0x82, 0xa, 0x2a, 0xa8, 0xa0, 0x82, 0xa, 0x2a, 0xa8, 0xa0, 0x82, 0xa, 0xf5, 0x17, 0x8c, 0x48, 0x6a, 0xe, 0x23, 0xd4, 0x73, 0xa5, 0x16, 0xe8, 0xba, 0x5f, 0xb, 0x74, 0xdf, 0xac, 0x87, 0x7a, 0x2f, 0x34, 0xc3, 0xfd, 0x9d, 0x66, 0x24, 0x71, 0x0, 0xca, 0xa2, 0x66, 0x34, 0xb3, 0xba, 0x37, 0x9e, 0x5f, 0x78, 0x92, 0x2e, 0x5f, 0x5, 0x3d, 0xd4, 0x77, 0xe6, 0x72, 0xd, 0xa7, 0x33, 0x50, 0x2a, 0xa3, 0x35, 0x9c, 0x5e, 0xd4, 0x1a, 0xcf, 0xfc, 0x19, 0x7c, 0xae, 0x35, 0x76, 0xbe, 0xa5, 0x5, 0x3a, 0x9f, 0xd5, 0x1a, 0xbb, 0x1e, 0xd4, 0x83, 0x3d, 0xb7, 0x1b, 0xe1, 0xbe, 0x4b, 0xcd, 0x48, 0xf2, 0x0, 0x4f, 0x2c, 0xe7, 0x9f, 0x4, 0x4b, 0x57, 0xc1, 0x13, 0x3f, 0x6b, 0x16, 0x8, 0xfc, 0xe9, 0x72, 0xd, 0x67, 0x94, 0xb4, 0xc6, 0x32, 0x67, 0x56, 0x41, 0x9e, 0xc, 0x2f, 0xeb, 0xfc, 0xa, 0xc6, 0x70, 0x97, 0xc7, 0xca, 0x2c, 0x3e, 0x8e, 0x53, 0x55, 0xc1, 0xb4, 0xb2, 0x1b, 0xeb, 0x70, 0xcd, 0x38, 0xb1, 0x29, 0x23, 0x92, 0x38, 0x79, 0xa4, 0xfd, 0xad, 0xbe, 0xff, 0x63, 0x53, 0x1b, 0xd1, 0xf4, 0x36, 0x7a, 0xa0, 0xf3, 0x77, 0x12, 0xb6, 0xe1, 0xc, 0x46, 0xb1, 0x94, 0x6, 0xac, 0x36, 0x26, 0x63, 0x28, 0xc2, 0x0, 0x1a, 0xd6, 0x3c, 0xf0, 0x89, 0xa9, 0x95, 0x32, 0x63, 0x18, 0x8c, 0x68, 0x66, 0x29, 0x23, 0x92, 0xdc, 0x5, 0xc2, 0x77, 0xe1, 0x7e, 0x7e, 0xaa, 0x2a, 0x4a, 0xa0, 0xf3, 0xf, 0xe4, 0xef, 0x30, 0x62, 0xf7, 0x1f, 0xec, 0x7d, 0x0, 0xfd, 0xfd, 0x83, 0xfe, 0x4a, 0x2, 0xea, 0xdf, 0x11, 0xee, 0x5, 0x7e, 0xc7, 0x55, 0x70, 0x4, 0xd2, 0xd3, 0x28, 0x95, 0xc6, 0xe6, 0xb4, 0xaf, 0x60, 0x46, 0x53, 0xbb, 0x18, 0xa1, 0xbe, 0xab, 0xb0, 0xd9, 0x3f, 0x83, 0xaa, 0x6b, 0xd6, 0x85, 0x8, 0xdf, 0x98, 0x56, 0x66, 0xbd, 0x61, 0x8f, 0x11, 0xcb, 0x2d, 0x36, 0x45, 0x9f, 0xc, 0x94, 0x6, 0x3, 0x1f, 0xfb, 0x2f, 0x23, 0xdc, 0x7f, 0x99, 0x1e, 0x18, 0x5d, 0x3, 0x50, 0xc2, 0x47, 0xb3, 0xcb, 0x43, 0xf8, 0x3d, 0xe1, 0xe6, 0xef, 0xc4, 0x26, 0x33, 0x50, 0x2, 0xd8, 0xf8, 0xae, 0x32, 0x8c, 0xc7, 0x94, 0xbf, 0x1c, 0x84, 0xc0, 0x9, 0x7e, 0xdc, 0x13, 0xcb, 0xcf, 0x3f, 0xf4, 0x97, 0x7f, 0x72, 0x7a, 0x33, 0x9a, 0xde, 0x1b, 0xfd, 0xd0, 0xe9, 0x47, 0x9f, 0x83, 0x86, 0xe6, 0x14, 0xe8, 0x2a, 0xe2, 0x1d, 0xf0, 0xa2, 0x27, 0x5e, 0x98, 0x56, 0xa9, 0x36, 0xa, 0x1, 0xaf, 0xea, 0xc5, 0x3d, 0xb1, 0x6c, 0xb, 0x4e, 0xfc, 0xdd, 0xd8, 0xdc, 0x12, 0x87, 0x8b, 0xce, 0xd3, 0x41, 0x21, 0x2, 0x44, 0x63, 0x4, 0xd2, 0x30, 0x98, 0x33, 0xe1, 0x9, 0x66, 0x1a, 0xd2, 0x78, 0x10, 0xe, 0x2f, 0xfa, 0x47, 0xf4, 0x60, 0x37, 0x84, 0xa4, 0xfe, 0x2a, 0xfd, 0xcb, 0x4, 0x44, 0x9a, 0x8b, 0xcf, 0xec, 0x34, 0xc6, 0xfe, 0xc1, 0xd7, 0x7a, 0xe1, 0x74, 0x4a, 0xbd, 0x51, 0x8, 0x10, 0x31, 0x3, 0x31, 0x4a, 0x53, 0xc0, 0x0, 0x17, 0x5e, 0xe4, 0xf3, 0x3c, 0x2a, 0xe3, 0x14, 0xc9, 0x8, 0xac, 0xac, 0x5, 0x61, 0x1c, 0xdd, 0xb1, 0xaf, 0xf5, 0xa2, 0xe9, 0x4c, 0x2b, 0x37, 0xbf, 0x27, 0x56, 0x58, 0x6, 0xc6, 0x66, 0x80, 0xd, 0xd1, 0xf6, 0x1f, 0xd1, 0x8f, 0xe8, 0xd3, 0x19, 0x31, 0x3e, 0x28, 0x95, 0xbd, 0x7, 0xfa, 0x55, 0x6, 0x30, 0x1a, 0x1, 0xae, 0xfc, 0xb, 0x3d, 0x20, 0x84, 0x1f, 0x4, 0x4c, 0x8, 0x82, 0x38, 0xd4, 0xfb, 0x11, 0xae, 0x82, 0xd5, 0x21, 0xec, 0xac, 0x38, 0xdd, 0xcb, 0x80, 0x55, 0xbc, 0xf1, 0xc2, 0x9a, 0xde, 0xa6, 0xc2, 0x5a, 0x65, 0xb1, 0xe1, 0x21, 0x3a, 0x60, 0x64, 0xdd, 0x78, 0x4c, 0x5e, 0x8b, 0xbb, 0xfb, 0x1, 0x78, 0x9a, 0x77, 0xe5, 0xbe, 0x6, 0xd, 0x79, 0x25, 0x1a, 0xf7, 0xaf, 0xd1, 0xb8, 0x2, 0x3c, 0x4d, 0xe7, 0xcc, 0xa2, 0x5e, 0xfb, 0xe1, 0xc4, 0xc3, 0xb8, 0x53, 0x8b, 0xa0, 0x4, 0x18, 0xc5, 0x32, 0x21, 0xe9, 0x3b, 0x0, 0xe1, 0x0, 0xd2, 0x24, 0x20, 0xee, 0xf5, 0xcb, 0x71, 0xaf, 0x1f, 0xd, 0x91, 0xef, 0x45, 0xde, 0xaf, 0xbc, 0x9e, 0x83, 0x90, 0x7c, 0x1c, 0xe0, 0x3c, 0x8e, 0x9c, 0xcf, 0xc7, 0x14, 0x75, 0xfe, 0x42, 0x5f, 0x23, 0x7a, 0x4, 0x7a, 0x9b, 0xce, 0x5a, 0x1a, 0xde, 0x6b, 0x6f, 0x18, 0xef, 0xf2, 0x75, 0xfe, 0x6, 0xc8, 0x9e, 0x82, 0x53, 0xf9, 0x43, 0x79, 0x73, 0x8d, 0x50, 0x6f, 0x15, 0x5d, 0x66, 0xa0, 0x7c, 0xb4, 0x41, 0x5c, 0xe4, 0x69, 0x81, 0x28, 0x23, 0xb1, 0x45, 0x1b, 0xa4, 0xed, 0x7c, 0xb9, 0x4c, 0x8c, 0xed, 0x38, 0x9e, 0x21, 0xc6, 0xf9, 0x1b, 0x1e, 0x60, 0x35, 0x33, 0x96, 0x5b, 0xc4, 0xdb, 0x7c, 0xee, 0xec, 0x43, 0x59, 0x2f, 0xea, 0xcf, 0xe2, 0x8d, 0x9f, 0x65, 0xea, 0xe1, 0xbe, 0x77, 0x78, 0xbf, 0x5f, 0x9a, 0xb1, 0xfc, 0x46, 0xde, 0xa6, 0xb3, 0x67, 0xa8, 0x4b, 0x3, 0xc0, 0xe2, 0xb7, 0x81, 0x1, 0x7c, 0x62, 0x88, 0xd, 0x66, 0x94, 0x1e, 0x1c, 0x8c, 0xb7, 0xb1, 0xd3, 0xf2, 0x77, 0x69, 0x94, 0xa9, 0xf1, 0x1e, 0xb8, 0x52, 0xde, 0xc1, 0x15, 0x73, 0x3a, 0xae, 0x1c, 0x1d, 0xcc, 0x8a, 0xbc, 0xff, 0xf4, 0xa, 0x38, 0xed, 0xb, 0xa2, 0xfe, 0xa1, 0x7a, 0x10, 0xfd, 0x10, 0x3d, 0xd5, 0xf9, 0x22, 0xff, 0x8, 0xfc, 0xef, 0x30, 0x5f, 0xfd, 0x79, 0x80, 0xa6, 0xb3, 0x97, 0xc1, 0x46, 0xbe, 0x5b, 0x39, 0x91, 0x10, 0x2d, 0xdc, 0x87, 0x8d, 0x96, 0x8, 0x3b, 0xe0, 0x58, 0x26, 0xb5, 0x1d, 0x29, 0x21, 0x82, 0xe6, 0x27, 0xf2, 0x78, 0x9a, 0x83, 0x77, 0xc6, 0x75, 0xf0, 0xa, 0x1b, 0x7a, 0x5b, 0xce, 0x9b, 0x7d, 0xa0, 0x5f, 0x9, 0x51, 0xa6, 0xe3, 0xaa, 0xba, 0x8f, 0xd7, 0x2f, 0xf2, 0xd8, 0xf6, 0x2c, 0xd4, 0x97, 0xc7, 0xca, 0xe4, 0x51, 0x6f, 0xa9, 0xfa, 0xf3, 0x2, 0x91, 0xe4, 0x6b, 0x7a, 0x79, 0x83, 0xab, 0x9b, 0xda, 0xcf, 0x41, 0xda, 0x19, 0x51, 0x67, 0xbc, 0x9, 0xf5, 0x31, 0xc2, 0x9e, 0x27, 0xd2, 0x95, 0xf9, 0x93, 0x21, 0x3c, 0xf, 0x11, 0x1b, 0xa4, 0xfb, 0x7e, 0x53, 0x94, 0x15, 0x1, 0xd5, 0x95, 0xfb, 0xe1, 0x6b, 0x29, 0x52, 0x1c, 0x49, 0x3d, 0x8c, 0xff, 0x29, 0xd6, 0xad, 0x2f, 0x3, 0x88, 0xa6, 0x1f, 0xe2, 0x1b, 0xc8, 0x45, 0x75, 0x3b, 0x10, 0x8d, 0x10, 0x79, 0x7c, 0xfe, 0x94, 0xaf, 0x93, 0xa0, 0xc9, 0x67, 0x60, 0x8, 0xdb, 0xe2, 0x6a, 0x68, 0xa5, 0xb2, 0x8a, 0xc8, 0x4c, 0xea, 0x8b, 0x11, 0xa2, 0xf, 0x6, 0x60, 0x4, 0x89, 0xf, 0xcc, 0x58, 0xa1, 0xa5, 0x8e, 0x1e, 0x82, 0xf9, 0x5d, 0xe1, 0x1e, 0x3f, 0xb5, 0x4f, 0x13, 0xc5, 0x13, 0x9, 0x31, 0x67, 0x56, 0xf5, 0x8, 0x38, 0xd1, 0xe0, 0x4f, 0x23, 0x9c, 0x0, 0x55, 0x8f, 0xc5, 0x78, 0x2c, 0x90, 0xda, 0x89, 0xba, 0x89, 0x6f, 0x60, 0x3c, 0x7, 0xd4, 0xcb, 0x3b, 0xc0, 0x84, 0x1, 0xbc, 0x42, 0x9b, 0x10, 0x49, 0x4c, 0x48, 0x20, 0x18, 0xab, 0xc4, 0xfd, 0x22, 0x3d, 0xe5, 0x37, 0x21, 0xca, 0x64, 0x50, 0xc6, 0xe4, 0x7e, 0xf4, 0x70, 0xe2, 0x73, 0x3c, 0x92, 0xf, 0x98, 0xec, 0xff, 0xcb, 0xc7, 0x70, 0xef, 0xbd, 0x86, 0x85, 0x17, 0xcb, 0x8b, 0x36, 0xb1, 0xf8, 0x9, 0xe, 0x93, 0xd3, 0xc3, 0xc0, 0xf6, 0x28, 0x48, 0x27, 0x3f, 0x81, 0x27, 0x38, 0x74, 0x92, 0x8a, 0x5f, 0xc8, 0xe0, 0xe4, 0x7f, 0x66, 0x9f, 0x2, 0x2c, 0x96, 0xf1, 0xb8, 0x9e, 0x21, 0x2f, 0x60, 0xef, 0x5, 0xe, 0xc7, 0x77, 0x78, 0x44, 0x9e, 0x30, 0x19, 0xff, 0xef, 0xbf, 0xdf, 0x8c, 0xa4, 0x7e, 0x31, 0xb0, 0x60, 0xc0, 0xc5, 0x47, 0x1c, 0x55, 0x88, 0xfd, 0xc0, 0x61, 0xb0, 0xb2, 0xf7, 0xfb, 0x5b, 0xcf, 0x77, 0xef, 0x8f, 0x44, 0xb0, 0xce, 0x6e, 0xb8, 0xf1, 0x13, 0xf0, 0xb, 0xd7, 0xdc, 0x83, 0xa9, 0xef, 0x6f, 0xbd, 0x60, 0x66, 0x2c, 0xea, 0xc1, 0xaa, 0xf0, 0xd1, 0x54, 0x19, 0x26, 0xd2, 0xa, 0xc0, 0xf7, 0x26, 0xfd, 0x15, 0x7e, 0x21, 0x3c, 0xd8, 0xb5, 0xe2, 0x43, 0xf4, 0xd5, 0x30, 0x49, 0xb8, 0xf0, 0xd4, 0xf, 0x10, 0xf5, 0x21, 0x3c, 0x58, 0x2e, 0x87, 0x31, 0x9c, 0x8c, 0xfc, 0xe5, 0x1c, 0xfe, 0xfc, 0x58, 0x16, 0xf5, 0x1e, 0xe6, 0x8b, 0x23, 0xd0, 0x96, 0x21, 0x6, 0x3, 0x6d, 0x44, 0x5a, 0xa4, 0x1d, 0xcb, 0x44, 0x1d, 0xc7, 0x6f, 0x30, 0xf8, 0xbe, 0xd3, 0x36, 0xe, 0x79, 0xce, 0xed, 0x6, 0x3f, 0x5f, 0xe7, 0x36, 0x6, 0x3f, 0x10, 0xa0, 0x7c, 0xfa, 0x6f, 0x5d, 0xbe, 0xfd, 0xa2, 0x99, 0xdd, 0x29, 0x7e, 0xcb, 0x85, 0xb3, 0xe3, 0xdf, 0xb6, 0x87, 0xb0, 0x80, 0x62, 0xed, 0x42, 0x33, 0x3f, 0x22, 0xff, 0x61, 0x18, 0x42, 0x2, 0x86, 0xd0, 0xe2, 0x6f, 0xbf, 0x68, 0xae, 0x4a, 0xfd, 0xf3, 0x56, 0xc2, 0x82, 0x9e, 0x94, 0x36, 0x85, 0x99, 0x56, 0xba, 0xc4, 0x51, 0x60, 0x3f, 0x80, 0x2d, 0xfe, 0xfb, 0xde, 0xe6, 0x73, 0xda, 0xdc, 0xfc, 0x7a, 0x3f, 0xdb, 0xb6, 0x60, 0x8f, 0x95, 0x61, 0x9c, 0xda, 0x93, 0x62, 0xe5, 0xde, 0x41, 0xbd, 0x2b, 0x40, 0x17, 0x8c, 0xe2, 0xbe, 0x4a, 0xdd, 0x34, 0xd5, 0x3, 0x76, 0x5b, 0x90, 0x16, 0x38, 0x7e, 0x67, 0xfe, 0x87, 0xb4, 0x8c, 0x63, 0x19, 0xcf, 0x77, 0x48, 0x3b, 0xd7, 0x1d, 0xfc, 0x5c, 0x9d, 0xe7, 0x3b, 0xe0, 0xba, 0xb8, 0xf8, 0xbc, 0xe, 0xa3, 0x7d, 0x89, 0x17, 0xce, 0x5d, 0x79, 0xa7, 0xab, 0xa7, 0x73, 0xa5, 0xf8, 0xbe, 0x96, 0xf3, 0x22, 0x34, 0x51, 0x12, 0x31, 0x23, 0x26, 0x2e, 0x16, 0x4e, 0x65, 0x44, 0x94, 0xc7, 0x94, 0x9f, 0x2d, 0xe2, 0xbb, 0xc6, 0x60, 0x14, 0x2, 0x3a, 0xfd, 0xd8, 0x1f, 0x6f, 0xbc, 0xf0, 0xa4, 0xaf, 0xe5, 0xfc, 0xd, 0x5c, 0x29, 0x3e, 0x1e, 0x71, 0x8b, 0xe3, 0x34, 0xbf, 0xc5, 0x5, 0x2d, 0x3, 0xb1, 0x21, 0x66, 0xc, 0x69, 0xe, 0xff, 0xa6, 0x32, 0x29, 0x5f, 0xe4, 0x59, 0x20, 0x36, 0x78, 0x44, 0x9b, 0x11, 0x62, 0x11, 0xa3, 0xd7, 0xc6, 0x12, 0xf1, 0xb0, 0xd6, 0x21, 0xd2, 0xd5, 0x83, 0x2, 0xd7, 0x7f, 0x90, 0x3b, 0x4f, 0x7e, 0xeb, 0x85, 0x33, 0x60, 0x72, 0xbd, 0x74, 0xaa, 0x69, 0xe2, 0x5c, 0x4c, 0x97, 0x62, 0xd6, 0x1a, 0x20, 0xe3, 0x79, 0x55, 0x44, 0x3d, 0xd7, 0xcc, 0x97, 0xf0, 0x36, 0xb9, 0xd0, 0x0, 0xfc, 0xed, 0x17, 0x4f, 0xb, 0xb7, 0xb4, 0x79, 0xed, 0x6, 0xe6, 0xdc, 0x2, 0x89, 0x2d, 0xa5, 0x1, 0xa5, 0x6b, 0x90, 0xda, 0x38, 0xaf, 0x43, 0xb4, 0xa7, 0xf4, 0x78, 0xad, 0x1, 0x94, 0xef, 0xff, 0x47, 0x7c, 0xad, 0x17, 0xac, 0xef, 0x2a, 0x3, 0x58, 0xbe, 0xfd, 0xe2, 0x85, 0xf1, 0x98, 0x7b, 0xca, 0x63, 0xfd, 0xcb, 0xbd, 0x39, 0x0, 0x3b, 0x8f, 0x45, 0x71, 0xbc, 0x9f, 0x6d, 0xd, 0xd6, 0xae, 0xd7, 0xb6, 0xed, 0xdd, 0x87, 0x6a, 0x6d, 0xdb, 0xb6, 0x8d, 0xc7, 0xba, 0xfd, 0xb4, 0xb6, 0x6d, 0xdb, 0xb6, 0xed, 0xde, 0xee, 0x2f, 0xed, 0x49, 0x5e, 0xa6, 0x93, 0x4f, 0x2f, 0x49, 0x1f, 0x32, 0xf3, 0x9f, 0x73, 0x73, 0x93, 0x1e, 0xfe, 0xef, 0xe9, 0x4d, 0xa6, 0xd5, 0x93, 0x73, 0x9d, 0xcd, 0xa4, 0x5c, 0x37, 0xd7, 0x6b, 0x60, 0x7e, 0xef, 0x37, 0xfc, 0xc0, 0x37, 0x5, 0x6a, 0x3f, 0xf7, 0x23, 0x9, 0xfd, 0x0, 0xbc, 0x2, 0x9e, 0xe6, 0xbd, 0xc5, 0xc3, 0xbe, 0xc6, 0xd6, 0x7, 0x79, 0xbe, 0xbe, 0x9f, 0x78, 0x90, 0x2d, 0x8f, 0x82, 0x67, 0x19, 0xbf, 0xce, 0xbd, 0x5f, 0xf0, 0x99, 0xff, 0x2a, 0x3a, 0x80, 0xb5, 0xd, 0xfb, 0x64, 0xb0, 0x88, 0x4f, 0xf4, 0x32, 0xb7, 0xeb, 0x75, 0x25, 0xed, 0x1c, 0x9f, 0xee, 0xd, 0x44, 0x52, 0xbd, 0xe3, 0xb7, 0x1, 0xe1, 0xfd, 0x1f, 0x1a, 0x0, 0x23, 0xb7, 0x16, 0x67, 0x4b, 0x38, 0x59, 0xd6, 0xe1, 0xab, 0x82, 0x79, 0xa4, 0x35, 0x4c, 0xd7, 0xe4, 0x73, 0x48, 0x81, 0xa1, 0xc3, 0x7c, 0xaf, 0xa1, 0x5f, 0xe6, 0x2c, 0xee, 0x17, 0x2, 0x32, 0xd6, 0x24, 0x30, 0x25, 0xf4, 0x6f, 0x92, 0xf7, 0x31, 0x5, 0x7d, 0x96, 0x56, 0x7a, 0x23, 0x8f, 0x9f, 0x67, 0xfa, 0x9a, 0x3a, 0x23, 0xf8, 0xbf, 0x26, 0x5f, 0x61, 0x4b, 0xfb, 0x23, 0xe9, 0x89, 0x24, 0x76, 0x94, 0xb7, 0x29, 0x39, 0x34, 0x14, 0xcf, 0x8f, 0x61, 0x3c, 0xd, 0x78, 0xb9, 0x67, 0x43, 0x5f, 0x63, 0xc7, 0xc1, 0xbc, 0xab, 0x48, 0x43, 0x8e, 0x7, 0xf9, 0xfc, 0xab, 0x10, 0xe6, 0xfb, 0x5a, 0xb2, 0x55, 0xfc, 0xec, 0xf2, 0x4f, 0x89, 0xaf, 0x96, 0xf1, 0xc8, 0x9c, 0x39, 0x6e, 0xa4, 0xc5, 0xbc, 0x71, 0x4d, 0xf4, 0x49, 0x9e, 0x79, 0x8c, 0xbe, 0x7a, 0xc9, 0xed, 0xae, 0x18, 0xd8, 0xf3, 0xed, 0x3f, 0x92, 0xe, 0x91, 0xd4, 0xd7, 0x2a, 0x4e, 0xeb, 0x81, 0x3, 0x76, 0xab, 0x95, 0x73, 0x43, 0x2, 0x39, 0x9f, 0xcb, 0x9c, 0x71, 0xcd, 0xfa, 0x7c, 0xee, 0x73, 0xaa, 0x66, 0x5e, 0x19, 0xfa, 0x1b, 0xae, 0xff, 0xe, 0x1f, 0x5f, 0xa2, 0x80, 0x19, 0x8a, 0xdd, 0x10, 0x8e, 0xe7, 0x47, 0xd8, 0xdb, 0xef, 0xa4, 0x97, 0xa3, 0x0, 0xa7, 0xb0, 0xe7, 0xb9, 0x1b, 0xbd, 0xef, 0x51, 0x98, 0xbf, 0x88, 0xd9, 0xec, 0x7, 0xe8, 0xca, 0x47, 0x4d, 0xcc, 0xf3, 0x8c, 0x4b, 0xe6, 0x6b, 0xa5, 0xe8, 0x12, 0x42, 0x37, 0xb4, 0x7c, 0x42, 0x2c, 0xbb, 0xf7, 0x6, 0x2, 0x6c, 0xc2, 0x6a, 0x28, 0xf1, 0xa6, 0xcf, 0x8, 0xb6, 0xce, 0x30, 0xdb, 0x55, 0x66, 0x1f, 0x58, 0xa9, 0x3f, 0xb0, 0x62, 0xdf, 0x64, 0x7f, 0x72, 0x4, 0x6f, 0xcd, 0x86, 0xbb, 0xb4, 0xf9, 0x5d, 0x92, 0x47, 0xdf, 0x2c, 0x64, 0x78, 0x9b, 0x3c, 0xfc, 0x29, 0x44, 0x30, 0x16, 0x82, 0xb, 0xb1, 0x1a, 0x64, 0xa7, 0x8b, 0x3d, 0xe2, 0x8f, 0xe4, 0x86, 0xf5, 0x2c, 0x1, 0x62, 0x85, 0x61, 0xbe, 0xa6, 0x64, 0x33, 0xc9, 0xfe, 0xcf, 0x5b, 0x71, 0xaa, 0x45, 0x69, 0x90, 0xb1, 0xeb, 0xc0, 0x8e, 0xd2, 0x65, 0xd7, 0xb8, 0xe5, 0xf, 0x7e, 0x5d, 0xfb, 0x1d, 0xed, 0x7b, 0xff, 0xba, 0x3d, 0x5, 0xc5, 0x8a, 0x83, 0xe9, 0xa, 0x1d, 0xd8, 0xfe, 0x52, 0xf3, 0x43, 0x5b, 0x10, 0xc8, 0x5a, 0x3f, 0x9d, 0x8e, 0xfd, 0x3f, 0x6c, 0xe6, 0x7a, 0x7e, 0x13, 0x18, 0xcb, 0x8d, 0x60, 0x25, 0x1c, 0x42, 0xf0, 0xa, 0x48, 0xe0, 0xad, 0xba, 0xa3, 0xf3, 0x8, 0xbc, 0xd5, 0x12, 0xe6, 0x7b, 0xac, 0xe7, 0xc, 0x3b, 0xa, 0x30, 0xd6, 0x93, 0xdc, 0xf6, 0x33, 0xdf, 0xd9, 0x97, 0xfa, 0x23, 0x99, 0xa1, 0x3d, 0xb3, 0x20, 0xf2, 0x23, 0xf9, 0x11, 0xcb, 0xeb, 0xf8, 0xf2, 0x87, 0x9e, 0xb, 0xa4, 0x4e, 0xd2, 0xda, 0x58, 0xe6, 0x12, 0xab, 0xc0, 0xf2, 0x1e, 0x20, 0x8b, 0xc, 0x5b, 0x2f, 0xd1, 0x85, 0xa7, 0x59, 0xfd, 0xcd, 0x3d, 0x10, 0xcd, 0xe, 0xa, 0x26, 0x66, 0xc, 0xf6, 0x37, 0x77, 0xe, 0x61, 0x3c, 0x34, 0x10, 0xcd, 0xd, 0x72, 0x91, 0x4, 0x79, 0x48, 0x90, 0x3c, 0x87, 0x60, 0x4b, 0xac, 0xbe, 0x4a, 0x61, 0x4, 0x65, 0xce, 0x2b, 0xd2, 0x29, 0x78, 0xbb, 0xf4, 0x29, 0xfd, 0x5c, 0x83, 0xbf, 0xb1, 0xed, 0x3b, 0x1e, 0x49, 0xd7, 0xec, 0x25, 0xef, 0x45, 0x8e, 0xc6, 0xa7, 0xef, 0x29, 0x52, 0x6d, 0xfc, 0x4e, 0xe4, 0xc2, 0x4c, 0xfa, 0x32, 0x5d, 0xe0, 0xd1, 0x4a, 0xd, 0xe2, 0xc5, 0x61, 0xd8, 0x1d, 0x1e, 0x8c, 0x15, 0xc6, 0x53, 0xf0, 0x15, 0x2, 0x91, 0xcc, 0x26, 0x6c, 0x6c, 0x77, 0x86, 0x20, 0xbb, 0x33, 0x7f, 0x12, 0x73, 0x1b, 0xd0, 0x15, 0x87, 0xb8, 0x16, 0x34, 0xc, 0x1b, 0x8a, 0xa1, 0x33, 0x70, 0x8e, 0xd6, 0xd4, 0x66, 0x10, 0x80, 0xb1, 0xf3, 0x40, 0x37, 0x52, 0x27, 0xc4, 0xbf, 0x7c, 0xf, 0x3f, 0x18, 0x4a, 0x14, 0xc7, 0x7b, 0x7a, 0xd1, 0xa1, 0x25, 0x1c, 0x1f, 0x3f, 0xd1, 0xa, 0x25, 0x79, 0x50, 0x86, 0xef, 0xf6, 0xe3, 0x37, 0x24, 0x5d, 0xe0, 0x4f, 0x48, 0xf0, 0x16, 0xdd, 0xef, 0x27, 0xce, 0x4d, 0xd7, 0x6a, 0xc7, 0x6d, 0xcf, 0x43, 0x8a, 0xd, 0x5d, 0xd, 0x3a, 0xb4, 0xfb, 0xac, 0xc1, 0x30, 0xee, 0x70, 0x56, 0xe3, 0x3f, 0x3a, 0x5b, 0x19, 0x97, 0x9d, 0x86, 0x4e, 0x2e, 0xc6, 0x14, 0xbf, 0xf3, 0x26, 0x4f, 0x2f, 0x3d, 0xe8, 0x48, 0xcb, 0xf8, 0x1a, 0xda, 0x5f, 0x17, 0x5f, 0x55, 0xd5, 0x77, 0xa4, 0xfd, 0xf8, 0xd, 0x9, 0x94, 0x9, 0xc6, 0x35, 0x8b, 0x71, 0x89, 0x8e, 0xb0, 0x8f, 0xfb, 0xef, 0x6, 0x76, 0x9f, 0x3d, 0x38, 0x18, 0xcd, 0x36, 0xf2, 0xd8, 0xc5, 0x2e, 0x5c, 0x73, 0xb8, 0x7d, 0xde, 0x30, 0x7, 0x38, 0x97, 0x39, 0xa0, 0x27, 0x11, 0xe6, 0x13, 0x5c, 0x73, 0xf2, 0x4e, 0x4f, 0x2f, 0x3f, 0x2, 0xb1, 0xdc, 0x12, 0x74, 0x28, 0xde, 0x3d, 0x48, 0xf1, 0xcd, 0xf1, 0x21, 0xad, 0xcf, 0xe7, 0x7d, 0x8f, 0xe8, 0x2, 0xe6, 0xeb, 0xd5, 0x39, 0x73, 0xde, 0xb5, 0xb1, 0x7e, 0xce, 0xe2, 0x3c, 0x67, 0x89, 0xe8, 0xad, 0x3, 0x5c, 0xf, 0x3a, 0xb4, 0xdb, 0x8c, 0x61, 0xb4, 0xa5, 0xcf, 0xb4, 0xf6, 0xa3, 0x3b, 0x69, 0x17, 0xe8, 0xd2, 0xf5, 0x28, 0xc6, 0x5a, 0xf1, 0xef, 0x5d, 0x3a, 0x71, 0x87, 0xb, 0xc1, 0xb8, 0xb2, 0x51, 0xf6, 0xd2, 0xa9, 0x1e, 0xd1, 0xf3, 0x21, 0xb2, 0x5e, 0x50, 0xba, 0x4d, 0x5e, 0x7e, 0x7d, 0x10, 0x8c, 0x65, 0x1b, 0xea, 0xd0, 0xfa, 0x72, 0x61, 0x8, 0xf0, 0x35, 0x28, 0xc3, 0x7e, 0xc7, 0x80, 0xbe, 0x12, 0x80, 0xc9, 0xa9, 0x3b, 0xf8, 0xce, 0x1f, 0xe7, 0xe9, 0x43, 0x7, 0x4f, 0x26, 0xd, 0x90, 0xe0, 0x1d, 0xc9, 0x89, 0x42, 0x2a, 0x89, 0xab, 0x2e, 0xc0, 0x5e, 0x5, 0xec, 0x3, 0xdc, 0xff, 0x21, 0x29, 0xef, 0x6, 0x1e, 0xe4, 0xf5, 0xe9, 0xbf, 0xe, 0x13, 0x80, 0xa4, 0x21, 0x9b, 0x93, 0xaf, 0xf0, 0xd4, 0xb1, 0xb9, 0xa7, 0xf, 0x1e, 0x90, 0xe0, 0x78, 0x56, 0xe1, 0xaf, 0x5a, 0x1c, 0x75, 0x2e, 0xbe, 0xe4, 0xf, 0x19, 0x49, 0x5f, 0xec, 0x6e, 0xfb, 0x8f, 0x17, 0xc6, 0x12, 0xe4, 0x4f, 0x55, 0xe3, 0x9d, 0x40, 0xa4, 0x2d, 0x18, 0x3a, 0x7e, 0x66, 0x77, 0x7d, 0x8c, 0xa7, 0x8f, 0x1e, 0x10, 0x77, 0x2c, 0x5, 0x68, 0x97, 0x78, 0x94, 0xc4, 0x26, 0xd2, 0x45, 0x60, 0x43, 0x0, 0x1, 0x52, 0xf7, 0xb2, 0x2f, 0x59, 0xde, 0x95, 0x0, 0xb5, 0x7f, 0xbf, 0xd2, 0x9a, 0x37, 0x80, 0x0, 0xbf, 0x6b, 0xc6, 0x2, 0xcd, 0x4, 0xd9, 0xdc, 0x89, 0xec, 0x3e, 0x8, 0xa0, 0xaa, 0x7, 0xc9, 0xae, 0x3a, 0xcd, 0xcb, 0x96, 0x29, 0x9e, 0x3e, 0x7c, 0x4, 0xe3, 0x85, 0xb5, 0x28, 0xc2, 0xe3, 0x46, 0x61, 0x9a, 0x91, 0xb, 0x9a, 0x13, 0x8b, 0x31, 0xd2, 0x72, 0xde, 0x9c, 0x47, 0x91, 0x7f, 0xb3, 0x88, 0x4e, 0x77, 0x25, 0x38, 0x94, 0xf, 0x44, 0xf9, 0x75, 0xb4, 0xe9, 0xbf, 0xab, 0x6, 0x93, 0x8e, 0x0, 0x5d, 0x4, 0x94, 0xfa, 0x90, 0xbd, 0xc5, 0xe, 0x9e, 0x7e, 0x70, 0xb0, 0x2, 0x8f, 0xaf, 0xc6, 0x94, 0x2c, 0x49, 0x8c, 0x75, 0x1, 0x36, 0x95, 0x26, 0xd9, 0x8, 0xa6, 0x5d, 0xfc, 0x5d, 0x60, 0xf2, 0xb, 0xd8, 0x87, 0xa1, 0x94, 0x16, 0x60, 0x19, 0xd9, 0x3d, 0x44, 0xb4, 0xcf, 0x57, 0x1c, 0x56, 0x9a, 0x1e, 0x88, 0x75, 0x1, 0xab, 0x67, 0x54, 0x7f, 0x20, 0x0, 0x71, 0x4, 0xd9, 0x8c, 0xdd, 0x6b, 0xe4, 0x87, 0x18, 0xe7, 0x92, 0x7, 0xa4, 0x13, 0x90, 0x7c, 0xa2, 0xf, 0x2, 0x4c, 0x5f, 0x7a, 0xe7, 0x96, 0x81, 0xce, 0x7, 0x96, 0x98, 0xbe, 0xb8, 0x5f, 0xa, 0x86, 0xa1, 0x8a, 0x31, 0xbb, 0xa8, 0xea, 0x4a, 0x7f, 0x45, 0xd2, 0x8c, 0x8d, 0x5f, 0x3f, 0x21, 0x41, 0xdc, 0x66, 0x9e, 0xba, 0x91, 0x47, 0x91, 0xd1, 0xcc, 0x5d, 0x81, 0x78, 0x61, 0x61, 0x67, 0x5f, 0x0, 0xed, 0x71, 0xe3, 0xe0, 0x40, 0xac, 0x10, 0xa3, 0x55, 0xff, 0x7, 0x24, 0xb0, 0x74, 0xb9, 0xbb, 0x40, 0x87, 0x21, 0x79, 0x8e, 0xbe, 0x90, 0x77, 0xb, 0x53, 0xfa, 0x13, 0x1, 0x58, 0x2c, 0xeb, 0x10, 0xdf, 0xb7, 0xa0, 0xec, 0x26, 0xc8, 0x9f, 0xd4, 0x21, 0xa5, 0x18, 0x4b, 0x5e, 0x33, 0xaf, 0x53, 0xab, 0xd, 0xdd, 0xd8, 0xe5, 0x5e, 0xd, 0xc3, 0x84, 0x0, 0x69, 0xfb, 0x68, 0xc6, 0x69, 0x58, 0x1b, 0x4a, 0x4c, 0xdf, 0xd5, 0xd3, 0xcf, 0x8e, 0xf0, 0xee, 0x33, 0x27, 0xb2, 0x61, 0x3e, 0x5d, 0x62, 0x55, 0x5a, 0xac, 0xee, 0x14, 0x5e, 0x8a, 0x8f, 0xd4, 0xc0, 0xea, 0x7f, 0x9f, 0xee, 0x73, 0x56, 0x30, 0x3e, 0x7d, 0x39, 0x9b, 0xc, 0x2e, 0xe, 0xf, 0xed, 0x36, 0x73, 0x51, 0x14, 0xad, 0x1f, 0x88, 0x17, 0x23, 0xc1, 0x78, 0xf1, 0x40, 0x56, 0xea, 0x1b, 0x18, 0x2c, 0x1, 0xcd, 0x90, 0x6d, 0x88, 0x9e, 0x4f, 0x43, 0x89, 0x19, 0x6b, 0x7a, 0xfa, 0xe1, 0x11, 0xde, 0x6d, 0xe6, 0xca, 0x5a, 0x8c, 0x8e, 0xe6, 0xcb, 0xac, 0x8b, 0xc2, 0x9b, 0xe6, 0xbe, 0xd, 0xc6, 0xf3, 0xb3, 0x58, 0x4c, 0xdb, 0xfb, 0xe2, 0x33, 0x7, 0x77, 0xa3, 0xe0, 0x33, 0xc6, 0x51, 0xec, 0x55, 0x29, 0xf4, 0xe, 0xb4, 0xaf, 0x4, 0xf2, 0x68, 0x98, 0xd4, 0xc9, 0xe6, 0xec, 0x9d, 0x40, 0x4, 0x63, 0x20, 0x18, 0x35, 0xa0, 0x19, 0x56, 0xda, 0xd8, 0x6, 0xaa, 0xce, 0xc7, 0xa, 0x47, 0x62, 0x7b, 0x74, 0x7f, 0x24, 0x0, 0xb, 0x68, 0x45, 0xf2, 0xf7, 0x83, 0xe4, 0xce, 0x9, 0x28, 0x73, 0xee, 0x91, 0xac, 0xfa, 0xcc, 0xf7, 0xd8, 0xb8, 0x8f, 0x7a, 0x1d, 0x1a, 0xde, 0x7d, 0xd6, 0xc4, 0xee, 0x32, 0x75, 0x1a, 0x2b, 0xfe, 0x30, 0x1e, 0xc3, 0xde, 0x92, 0x62, 0xeb, 0xc0, 0x68, 0x56, 0x87, 0x32, 0xcf, 0xd9, 0x84, 0x2, 0x15, 0x5d, 0x7c, 0xf7, 0xaf, 0xe6, 0xe9, 0xa7, 0x7, 0xc4, 0x5e, 0x96, 0xe2, 0x3c, 0x23, 0x39, 0x53, 0x8e, 0xe4, 0x4d, 0xea, 0x80, 0xde, 0x2f, 0x59, 0xf1, 0x4f, 0x51, 0xf8, 0x13, 0x58, 0xb0, 0xa3, 0x6c, 0xb6, 0xaa, 0x19, 0xff, 0x73, 0x77, 0xce, 0x51, 0x96, 0x2b, 0x69, 0x0, 0x3f, 0xe7, 0xd9, 0xb6, 0xed, 0x77, 0xb5, 0xb6, 0x6d, 0x7b, 0xdb, 0x5a, 0xdb, 0xb6, 0x6d, 0x7b, 0x9b, 0xd7, 0xcd, 0x35, 0x9f, 0xcd, 0xb1, 0x6d, 0xab, 0xbb, 0xb2, 0xbf, 0x4a, 0xbe, 0x4c, 0x32, 0x75, 0x36, 0xe7, 0x4e, 0xcf, 0xad, 0x34, 0xf2, 0xc7, 0xef, 0x54, 0xa5, 0x92, 0xfb, 0xb9, 0xaa, 0x82, 0xc1, 0x5b, 0x49, 0xfe, 0x3a, 0x84, 0x22, 0x98, 0xa, 0x3, 0x1e, 0x25, 0x1c, 0x4d, 0xa8, 0x2f, 0xfc, 0x1e, 0x22, 0x8e, 0x27, 0x89, 0xd6, 0xc7, 0x2c, 0x79, 0x6c, 0x52, 0xb, 0x0, 0xdf, 0x4e, 0x25, 0x41, 0x9f, 0xc2, 0xcf, 0x88, 0x18, 0xfc, 0x5e, 0x30, 0x8e, 0x5, 0xf3, 0x5c, 0x38, 0x6e, 0x24, 0xfd, 0xbd, 0xd7, 0xbd, 0xb1, 0xfb, 0x70, 0x5b, 0x5f, 0xf7, 0x3e, 0x4d, 0x1, 0xf0, 0x1a, 0x36, 0x30, 0x82, 0xbe, 0x92, 0x7e, 0x6c, 0xf0, 0xc2, 0x64, 0xd7, 0x8d, 0x8d, 0x7d, 0x8f, 0x12, 0x33, 0x92, 0x5a, 0x4, 0x4f, 0x94, 0xb8, 0x5a, 0x8b, 0x27, 0xb9, 0xda, 0x74, 0x63, 0x43, 0xdf, 0xa9, 0x16, 0x97, 0xaa, 0xee, 0x9f, 0x22, 0x14, 0xe1, 0x7f, 0x70, 0xa4, 0xd, 0x61, 0x1c, 0xd7, 0x42, 0x8c, 0xac, 0x71, 0x5e, 0xc9, 0xf1, 0xd2, 0x54, 0x63, 0x7f, 0x3a, 0xc9, 0x5, 0xc0, 0xbe, 0x7c, 0x6d, 0x10, 0x57, 0x30, 0xe2, 0x74, 0x70, 0xf1, 0xa2, 0x15, 0x19, 0x1a, 0x96, 0xfe, 0xed, 0x99, 0xe6, 0xfc, 0xb9, 0x16, 0x5f, 0x5a, 0x74, 0xf7, 0x6a, 0x45, 0x8, 0xd6, 0x28, 0x69, 0xa7, 0x80, 0x3f, 0xde, 0x94, 0x6a, 0xea, 0xbf, 0x3a, 0xd1, 0x5, 0xd0, 0x9c, 0xbf, 0x6, 0x5f, 0x27, 0x2c, 0xc7, 0x6e, 0x77, 0xba, 0x69, 0xe0, 0x3c, 0x8b, 0xcb, 0x54, 0x6f, 0x51, 0xaa, 0x4c, 0xf1, 0xb5, 0xcf, 0x89, 0x1b, 0xf4, 0x78, 0x6d, 0x43, 0xcf, 0x40, 0xaa, 0x69, 0xe0, 0xe2, 0x24, 0x17, 0x0, 0x33, 0xf5, 0x4a, 0x7c, 0x5d, 0x2f, 0x3e, 0xdb, 0x62, 0x3c, 0xdd, 0x3c, 0xad, 0x5, 0xd0, 0x1d, 0x3d, 0x2e, 0x44, 0x9f, 0xb, 0x40, 0xef, 0xf7, 0xd8, 0x2, 0xce, 0x4e, 0xf8, 0xa, 0x70, 0x19, 0x2b, 0xec, 0x82, 0x20, 0x6, 0xd2, 0x46, 0xc7, 0x25, 0x32, 0xd6, 0x37, 0xa, 0x29, 0xa0, 0xb0, 0xce, 0xb7, 0x79, 0xa3, 0x52, 0x14, 0xe1, 0xea, 0x0, 0x43, 0x1a, 0xa4, 0x8d, 0xa2, 0x21, 0x7a, 0xac, 0xd6, 0xef, 0x5d, 0x7d, 0xd, 0xc9, 0x2f, 0x80, 0x54, 0x93, 0x14, 0x0, 0x3e, 0xd7, 0x4b, 0x50, 0x0, 0xdd, 0x14, 0x40, 0xc1, 0x5e, 0x1, 0xa4, 0x75, 0x1, 0x78, 0xa, 0x94, 0x4e, 0x9a, 0x1, 0xf4, 0x84, 0xe8, 0x3e, 0x34, 0x8c, 0xdf, 0x6a, 0x7d, 0x14, 0x40, 0x9e, 0x0, 0x5d, 0x9c, 0xec, 0x15, 0xa0, 0x70, 0x25, 0xbe, 0x6e, 0xa8, 0x15, 0x1b, 0xa8, 0xd1, 0x7, 0xe9, 0x23, 0x6f, 0x3c, 0xd5, 0x68, 0x75, 0xb, 0xe8, 0xeb, 0xe5, 0x8d, 0x1c, 0x82, 0x5d, 0x25, 0xa, 0x9c, 0x98, 0x11, 0x5d, 0xbd, 0x37, 0x11, 0xa0, 0x44, 0xdf, 0x4, 0x66, 0x5a, 0x8a, 0xd7, 0xe8, 0x98, 0xe2, 0xaf, 0xcd, 0xd8, 0xed, 0x4e, 0x59, 0xbd, 0x9, 0x6c, 0xea, 0xff, 0xe9, 0x8d, 0x5a, 0x30, 0xb0, 0x2f, 0x7, 0xec, 0x3f, 0xa6, 0x5, 0x12, 0x6, 0x72, 0x2c, 0xd7, 0x4, 0x63, 0x26, 0xe6, 0xb5, 0xe1, 0xeb, 0x9, 0x8, 0xb2, 0xe9, 0x2f, 0xa5, 0x0, 0x52, 0xc9, 0x2e, 0x80, 0xc2, 0xb5, 0x7e, 0xc, 0x25, 0x1e, 0x26, 0x46, 0xbc, 0x8c, 0x6b, 0x18, 0xf3, 0x5a, 0x81, 0x3e, 0xb1, 0xdb, 0x4e, 0xdc, 0xce, 0xb5, 0xf8, 0xac, 0x9a, 0xff, 0x34, 0x8a, 0xb6, 0x84, 0x92, 0x1e, 0x37, 0x52, 0xc9, 0x3d, 0xbb, 0x52, 0xcd, 0x85, 0x47, 0x25, 0x7c, 0x5, 0x78, 0x8a, 0xf8, 0xab, 0xec, 0xc5, 0xae, 0x77, 0x13, 0x5, 0x70, 0xb2, 0xc5, 0x15, 0x60, 0xe0, 0x2d, 0x6c, 0x3, 0xeb, 0x74, 0xb5, 0x71, 0x3f, 0x0, 0xbd, 0xca, 0x6d, 0x41, 0xc6, 0xac, 0xe3, 0xaf, 0x1c, 0x38, 0xf2, 0xd8, 0xc4, 0xee, 0xff, 0x2d, 0xc5, 0xd3, 0x88, 0xed, 0x67, 0x6d, 0xc7, 0x90, 0x89, 0x43, 0xdc, 0xf2, 0x5f, 0xe6, 0x25, 0xd3, 0x61, 0x76, 0xaa, 0xb4, 0xb5, 0x74, 0x1, 0x37, 0x63, 0x9d, 0xbc, 0x5c, 0xf8, 0x7b, 0xa, 0x5, 0x1, 0x18, 0x2e, 0x7d, 0xbe, 0x6f, 0xab, 0xb4, 0xd7, 0x42, 0xbf, 0x10, 0x36, 0xac, 0x5f, 0xda, 0x10, 0xe6, 0xf5, 0x72, 0xd, 0x72, 0x15, 0xc7, 0x9e, 0xdc, 0xe6, 0x62, 0x52, 0xb, 0x80, 0xb8, 0x96, 0xaf, 0x61, 0x7b, 0xbd, 0xfd, 0x46, 0xb7, 0x0, 0x24, 0x5e, 0x12, 0xb3, 0x50, 0x1f, 0xcc, 0x78, 0x1a, 0xc8, 0x78, 0x28, 0x7e, 0xd0, 0xb7, 0x89, 0x7c, 0xfd, 0x83, 0x42, 0xf8, 0x6c, 0xba, 0xa5, 0x74, 0x8a, 0x8d, 0x6a, 0x3d, 0x1e, 0x41, 0x37, 0x30, 0x23, 0x9f, 0x9b, 0x6e, 0x29, 0x34, 0xd2, 0x7e, 0x12, 0xe1, 0xbf, 0xc4, 0x81, 0x3b, 0x30, 0x6e, 0xf, 0x38, 0x3e, 0x28, 0x57, 0xb4, 0x1a, 0xa7, 0xe, 0x94, 0x57, 0x0, 0x85, 0xf, 0x64, 0xdb, 0xaa, 0x27, 0x26, 0xb3, 0x0, 0x4a, 0x39, 0x9d, 0x28, 0x10, 0x9f, 0xeb, 0x23, 0x15, 0x9e, 0x8c, 0xc1, 0xd8, 0x16, 0xa, 0xe1, 0x6f, 0x4c, 0xe0, 0xf7, 0x90, 0xc3, 0x33, 0xac, 0x19, 0x9f, 0x6b, 0x1f, 0x3c, 0x91, 0xa, 0xbe, 0x98, 0x19, 0xfa, 0x38, 0xda, 0x97, 0xd2, 0xb6, 0xa3, 0xe8, 0x7e, 0x14, 0x4e, 0xa0, 0xd8, 0x9a, 0x43, 0x14, 0xd8, 0xca, 0x6c, 0x6b, 0xf9, 0x9, 0x9, 0xdd, 0x2, 0x1e, 0xe5, 0x27, 0xdf, 0x52, 0x11, 0x28, 0x21, 0x98, 0x88, 0x22, 0x9b, 0x8f, 0x6a, 0x1b, 0xd8, 0x6e, 0xca, 0xe8, 0x7c, 0x4d, 0xae, 0xad, 0x7c, 0x64, 0x5c, 0xe, 0x7d, 0x87, 0x22, 0x18, 0x7, 0x9d, 0x38, 0x87, 0xb6, 0x2e, 0x90, 0xa1, 0xc0, 0x61, 0xe5, 0x79, 0x4d, 0xd2, 0x92, 0xcf, 0xaa, 0x76, 0x3a, 0xf1, 0xfa, 0x9c, 0xc4, 0x49, 0x4d, 0x3e, 0x3e, 0x35, 0xe3, 0xab, 0xcc, 0x38, 0x8a, 0xae, 0x25, 0xe8, 0xfd, 0x52, 0xba, 0xa5, 0x7c, 0x83, 0x55, 0x87, 0x72, 0x9d, 0x23, 0x47, 0x30, 0x53, 0xdf, 0x80, 0x61, 0xe3, 0xae, 0xa2, 0xe6, 0x1, 0x5, 0xce, 0xc1, 0x93, 0x17, 0xa4, 0xef, 0xc9, 0x70, 0xc1, 0xe0, 0x6f, 0x66, 0xdb, 0xca, 0x67, 0x27, 0xab, 0x0, 0x2a, 0x4f, 0x26, 0x19, 0xeb, 0x3, 0x3f, 0xf3, 0x66, 0x1c, 0x26, 0x43, 0xf4, 0x6f, 0x49, 0xbe, 0xf4, 0x69, 0xc1, 0xd5, 0x97, 0x7f, 0x88, 0xed, 0xe7, 0x59, 0x71, 0xdc, 0xd4, 0x5c, 0xe2, 0x57, 0x1e, 0xef, 0xa2, 0x15, 0x38, 0x36, 0xc0, 0xe0, 0xb5, 0xc8, 0x7e, 0x41, 0xc2, 0xf6, 0xff, 0x26, 0x99, 0xa1, 0x76, 0xe2, 0x24, 0xa4, 0xa3, 0xcf, 0x29, 0xf0, 0x56, 0x84, 0xe6, 0xfc, 0x70, 0xb6, 0xbd, 0x7a, 0x41, 0x5c, 0x2f, 0x36, 0x56, 0x84, 0x95, 0xd1, 0x1a, 0x14, 0x4, 0xfa, 0x46, 0xb, 0xe6, 0xb8, 0xd2, 0x20, 0x7, 0xc7, 0x8a, 0xdf, 0xc8, 0xb4, 0x55, 0x4f, 0x4e, 0xc4, 0xde, 0xdf, 0x5a, 0x4e, 0xe3, 0xcf, 0x5f, 0xd3, 0x4d, 0x92, 0x34, 0x29, 0x82, 0x38, 0x11, 0x5d, 0x12, 0xcb, 0x42, 0x8f, 0xfc, 0x27, 0x96, 0xd6, 0xbf, 0x6c, 0x1d, 0x96, 0x69, 0x29, 0xfd, 0x80, 0x76, 0xf, 0x38, 0x14, 0x83, 0x15, 0x90, 0x5, 0x85, 0xa5, 0xec, 0x5b, 0xaf, 0x4c, 0xc8, 0xe3, 0xdf, 0x47, 0x24, 0x3e, 0x4a, 0xda, 0x29, 0x1, 0x5d, 0xa2, 0xaf, 0xf4, 0xeb, 0x58, 0x1c, 0xd3, 0xff, 0x3a, 0x55, 0xa6, 0xb5, 0xf2, 0x54, 0x1e, 0x39, 0x76, 0x90, 0x30, 0x14, 0x15, 0x95, 0x28, 0x17, 0x8a, 0x61, 0x6a, 0x18, 0x5c, 0xf4, 0x8d, 0x76, 0xe5, 0x68, 0x79, 0x2c, 0x9b, 0xbf, 0x47, 0xfe, 0x39, 0xb3, 0x3b, 0xf9, 0x95, 0x27, 0xe3, 0xcf, 0xcd, 0x7e, 0x42, 0x82, 0x38, 0xd0, 0xd6, 0x8e, 0x55, 0x8d, 0x31, 0xe3, 0xd8, 0x40, 0x26, 0xd2, 0x2e, 0xee, 0x3f, 0x3e, 0x19, 0xdf, 0xcd, 0x4d, 0xfb, 0xd0, 0x89, 0xbc, 0xbe, 0xdd, 0x24, 0x5, 0xe0, 0x48, 0x5b, 0x17, 0xfb, 0x65, 0xb5, 0x14, 0xb7, 0x13, 0xc0, 0x8f, 0xcc, 0xd6, 0xe4, 0xe7, 0x3a, 0x86, 0x4e, 0x66, 0xf6, 0xff, 0x42, 0xfc, 0x91, 0xe4, 0x4f, 0x9, 0xca, 0x9f, 0x44, 0xc4, 0x70, 0x8c, 0x18, 0xa6, 0xe2, 0x5e, 0xe2, 0x46, 0x51, 0xb4, 0x17, 0xf4, 0xac, 0xb5, 0x81, 0xd2, 0xa4, 0x5d, 0x67, 0x4a, 0xf, 0xe2, 0xc0, 0x8b, 0x67, 0xe9, 0xa3, 0xdf, 0xc7, 0xf0, 0x61, 0x47, 0xfd, 0x71, 0x29, 0x4e, 0xfe, 0x3a, 0x89, 0x1f, 0xf7, 0x1f, 0x5f, 0x9d, 0x8a, 0x4a, 0xbf, 0x6, 0x65, 0xab, 0x33, 0x35, 0x1c, 0xcd, 0xa, 0xc6, 0x58, 0xe4, 0x31, 0xc9, 0x9f, 0xf0, 0xb6, 0x82, 0xf2, 0xf0, 0x23, 0x3a, 0x87, 0x4f, 0x9a, 0x55, 0xc9, 0x6f, 0x1f, 0x6c, 0xc0, 0xfe, 0x85, 0xe2, 0x8b, 0x3b, 0x23, 0xa3, 0x7c, 0xae, 0x35, 0x6e, 0x9e, 0x97, 0x36, 0x1a, 0x3f, 0xf, 0x5e, 0x1, 0x7c, 0x32, 0x76, 0x67, 0x1f, 0xd9, 0x35, 0x76, 0x34, 0x2f, 0x6f, 0x96, 0x7b, 0xc6, 0x95, 0xad, 0x40, 0xf0, 0x94, 0xb4, 0x1e, 0x6d, 0x95, 0xa1, 0x59, 0xb4, 0xf4, 0x3f, 0x86, 0x7d, 0xf7, 0x56, 0x89, 0x87, 0x2, 0x67, 0xa, 0x51, 0x1a, 0x1d, 0x33, 0x26, 0xce, 0x5c, 0x9e, 0xa4, 0x5e, 0x11, 0xab, 0xb3, 0x8f, 0xe8, 0xfa, 0xd3, 0x11, 0x54, 0x7b, 0x27, 0xca, 0x36, 0x83, 0x93, 0x6d, 0xb3, 0x87, 0xe, 0x20, 0x2d, 0x33, 0x47, 0xfa, 0xed, 0xd5, 0xea, 0xcc, 0x4f, 0xfe, 0x70, 0x8e, 0x2d, 0xeb, 0x1e, 0xdf, 0x76, 0x90, 0xb6, 0xae, 0x38, 0x44, 0xca, 0x89, 0x1a, 0xf7, 0x72, 0x31, 0xf8, 0xb9, 0x78, 0x9d, 0xed, 0x1a, 0x3b, 0x82, 0x6a, 0xff, 0x30, 0xca, 0xf6, 0x7a, 0xa, 0x2b, 0x4a, 0x5a, 0x6b, 0x84, 0xe5, 0xa6, 0x5b, 0xd0, 0xd3, 0x56, 0x2d, 0xcc, 0xdc, 0x65, 0x7f, 0x38, 0x4b, 0x91, 0xce, 0xd1, 0xb6, 0x82, 0x12, 0x1f, 0x94, 0xa5, 0x38, 0x28, 0x5f, 0xae, 0x81, 0x13, 0xc1, 0x38, 0xb9, 0x69, 0x8f, 0xd3, 0xd9, 0xa3, 0x98, 0xf9, 0x5f, 0xa2, 0xda, 0xc7, 0x41, 0x12, 0x55, 0x55, 0xf4, 0x75, 0x2b, 0x84, 0xfb, 0xe1, 0x31, 0xf3, 0x9a, 0xe8, 0xeb, 0x90, 0x17, 0xc8, 0xe5, 0x58, 0xf4, 0xdd, 0xc4, 0xd3, 0xc7, 0x69, 0x33, 0x6b, 0xe6, 0x8f, 0x3c, 0x83, 0xfd, 0x76, 0x19, 0xb6, 0x19, 0x13, 0xa1, 0xaa, 0x20, 0xc2, 0x3f, 0x21, 0x7a, 0x4c, 0xc0, 0x6f, 0x66, 0x39, 0x68, 0xff, 0x77, 0x72, 0x7c, 0x3f, 0x13, 0x61, 0x5, 0x13, 0x62, 0x27, 0x5b, 0xaf, 0x1e, 0x73, 0xf1, 0xfa, 0x65, 0xb7, 0xcf, 0xf9, 0x3b, 0xb2, 0x1d, 0xc3, 0x4f, 0x8f, 0x69, 0xd9, 0x1f, 0x3b, 0x8e, 0x4, 0x7c, 0x27, 0xdd, 0x5a, 0x99, 0xc8, 0x60, 0x1c, 0x55, 0xef, 0x3a, 0x2a, 0xfd, 0x43, 0xa3, 0xcd, 0xe8, 0xb, 0xa6, 0x5c, 0xfa, 0x8a, 0x40, 0x43, 0x65, 0x43, 0xa6, 0x7d, 0x68, 0x46, 0x7c, 0x35, 0xcc, 0xb4, 0xd, 0x7e, 0x8a, 0x80, 0x6f, 0xd4, 0x76, 0x82, 0x97, 0x74, 0xb1, 0xb5, 0xb6, 0xcf, 0xb5, 0x10, 0x59, 0x81, 0xec, 0x7f, 0x7b, 0xdf, 0x62, 0x46, 0x8f, 0xce, 0x76, 0x78, 0xf0, 0x5d, 0xe6, 0x1c, 0xa, 0xf0, 0x6, 0xe2, 0xf1, 0x64, 0x92, 0xfe, 0x12, 0x72, 0xf3, 0x56, 0xda, 0xc7, 0x30, 0x76, 0x78, 0xc, 0xc9, 0x1f, 0x3d, 0x81, 0x7d, 0xee, 0x93, 0xcc, 0xfe, 0xa0, 0xb2, 0xe9, 0x83, 0x73, 0xf0, 0x54, 0xa5, 0x9d, 0x14, 0x4a, 0x74, 0x86, 0x67, 0xd6, 0x16, 0x9c, 0xed, 0x79, 0xf4, 0xbb, 0x6e, 0x8a, 0x7e, 0xcd, 0x19, 0xef, 0xfd, 0xcf, 0xd1, 0xe8, 0x9f, 0xeb, 0xcd, 0xca, 0xfd, 0x3e, 0x29, 0xeb, 0x31, 0xc1, 0x57, 0xdd, 0xb2, 0xa4, 0xdf, 0x49, 0xe2, 0x4f, 0xfd, 0x7f, 0xb6, 0xe8, 0x18, 0x60, 0xc7, 0x61, 0xe4, 0xe7, 0x70, 0xf2, 0x73, 0x24, 0xd7, 0x1f, 0x66, 0xdd, 0x61, 0xaa, 0xea, 0x78, 0xe8, 0xe4, 0xe6, 0x62, 0x42, 0x3b, 0x99, 0xc3, 0x49, 0x8d, 0xf4, 0xe3, 0x45, 0x2, 0x21, 0x7d, 0x25, 0x38, 0xb0, 0x87, 0xc0, 0x2c, 0xcd, 0x52, 0x94, 0xa9, 0x96, 0xca, 0x91, 0x53, 0x91, 0x78, 0x66, 0x1a, 0x1, 0x1e, 0x2a, 0xa2, 0x77, 0x65, 0x78, 0xb5, 0xf2, 0x6d, 0xb2, 0x85, 0x11, 0xdb, 0x7d, 0xe8, 0xfc, 0xcd, 0x74, 0xef, 0x73, 0x4f, 0xcf, 0xba, 0xc6, 0xc, 0xb9, 0x15, 0xae, 0xdb, 0x30, 0x4, 0xc4, 0x3c, 0x6, 0xa3, 0xf, 0x91, 0xbf, 0x33, 0xae, 0x8d, 0xb8, 0x46, 0x85, 0xce, 0x2b, 0x19, 0xd3, 0xf6, 0x6c, 0xa5, 0xf2, 0xef, 0x63, 0x39, 0xfc, 0x44, 0xae, 0x73, 0xec, 0xc4, 0x98, 0xb6, 0xbe, 0x2c, 0x85, 0xf6, 0x1b, 0x96, 0xfc, 0x85, 0x2c, 0xf9, 0x7b, 0xfd, 0x19, 0xea, 0xdb, 0x22, 0x31, 0x89, 0xf0, 0x25, 0x2a, 0x46, 0x35, 0xe3, 0x25, 0x2b, 0xc9, 0xd0, 0xdf, 0x1f, 0xf5, 0xb6, 0xbf, 0x1e, 0x3d, 0xbd, 0x77, 0xb9, 0x1d, 0x23, 0xd7, 0x63, 0xc8, 0x9d, 0xbe, 0x71, 0xfe, 0xb2, 0x2c, 0xc7, 0x53, 0xc9, 0x1, 0x3a, 0x7d, 0x1b, 0x24, 0x50, 0x9b, 0x28, 0x84, 0xb9, 0x24, 0xea, 0x57, 0xd8, 0xfb, 0x4a, 0xf6, 0xc8, 0x93, 0xeb, 0xf4, 0x39, 0x45, 0xe1, 0x7f, 0x94, 0xc2, 0xfa, 0x1b, 0xb2, 0x17, 0xc1, 0x2e, 0x3f, 0xf1, 0xa2, 0xd7, 0xd7, 0x6d, 0xdd, 0xc7, 0xc0, 0xaf, 0xa1, 0xc5, 0xe8, 0x7f, 0xf3, 0xcc, 0xb8, 0xdb, 0xed, 0x1c, 0x7d, 0x3e, 0x6, 0x39, 0x30, 0x41, 0xa0, 0x9d, 0x69, 0x46, 0xb9, 0x48, 0x5f, 0xec, 0xd2, 0x7d, 0xdd, 0xee, 0xa6, 0x8, 0x16, 0xc3, 0xed, 0x30, 0x44, 0x22, 0xbf, 0xc9, 0xc, 0x7e, 0x1d, 0xab, 0x43, 0x9a, 0xfe, 0x85, 0xf4, 0x4f, 0xcd, 0x75, 0xfd, 0xe9, 0x44, 0x38, 0xee, 0x91, 0x6f, 0xfd, 0xcb, 0x89, 0x8c, 0x9d, 0x41, 0xb1, 0x5c, 0xc4, 0xf8, 0xe3, 0xd8, 0x47, 0xdf, 0xc3, 0xf1, 0x0, 0xbf, 0xbb, 0x9, 0xee, 0x67, 0xc6, 0xaf, 0xf7, 0x65, 0x83, 0xa9, 0x57, 0x8f, 0x49, 0xbf, 0x7e, 0x4c, 0x79, 0xf4, 0x27, 0xb0, 0xe5, 0x7f, 0xed, 0x9c, 0x3, 0x90, 0x2c, 0x49, 0x13, 0x80, 0xfb, 0xff, 0xcf, 0xb6, 0x6d, 0x6b, 0x7a, 0xe6, 0x6c, 0xdb, 0xb6, 0x6f, 0x7d, 0xb6, 0x6d, 0xdb, 0x76, 0xe0, 0x7c, 0xb7, 0xec, 0x99, 0xd5, 0xd9, 0xb6, 0x6d, 0x63, 0xdf, 0x54, 0xdd, 0x57, 0xbd, 0x39, 0x13, 0xf5, 0x2a, 0x5e, 0x5f, 0xaf, 0x63, 0xd0, 0x19, 0xf1, 0x45, 0x66, 0x55, 0x67, 0xd6, 0x54, 0x67, 0x66, 0xf5, 0xcc, 0xf2, 0x8a, 0xb5, 0x8f, 0x7b, 0xf9, 0x7f, 0x5e, 0x29, 0x8, 0x49, 0x9a, 0x8d, 0xd, 0x75, 0x93, 0x18, 0x4d, 0x57, 0x2, 0x9b, 0x24, 0x19, 0x46, 0x8f, 0xd, 0x4f, 0x58, 0xc8, 0x9c, 0xec, 0xc1, 0xb5, 0xd1, 0x36, 0xbf, 0x11, 0xf3, 0x1, 0x7b, 0x7f, 0x9e, 0x2f, 0x61, 0x7b, 0xfd, 0x9a, 0x27, 0x72, 0x7e, 0x4d, 0x73, 0x0, 0x1d, 0x8c, 0x3, 0x4e, 0x79, 0x27, 0xf4, 0x72, 0xfd, 0x65, 0x7c, 0xbf, 0x2, 0xed, 0xc2, 0x9a, 0xb2, 0xee, 0xf0, 0xef, 0x1, 0xed, 0xe2, 0xee, 0x3d, 0xf, 0x9a, 0x3d, 0x35, 0xaf, 0x50, 0xd3, 0x3c, 0xaf, 0x57, 0x2a, 0xc2, 0x9, 0x9a, 0x88, 0x6f, 0x0, 0xad, 0x27, 0x49, 0x51, 0x6, 0x29, 0x48, 0x29, 0x61, 0xf6, 0x55, 0xb4, 0xad, 0xf9, 0x62, 0x31, 0xa3, 0xe6, 0x42, 0x6d, 0xc7, 0x5a, 0xf1, 0x63, 0x75, 0xaf, 0x92, 0x57, 0x63, 0x77, 0xfa, 0x75, 0xad, 0xa5, 0xf7, 0xb, 0xb2, 0x3c, 0x5, 0x26, 0x81, 0x73, 0xe9, 0x4e, 0x1d, 0x52, 0xd3, 0xac, 0x38, 0x49, 0x46, 0x6b, 0xdf, 0x82, 0x31, 0xd8, 0x63, 0x57, 0x8b, 0x1d, 0xed, 0x67, 0x13, 0xbd, 0x66, 0xc4, 0x7a, 0xae, 0x2f, 0x7b, 0xb5, 0xed, 0x22, 0xe2, 0x8f, 0x4d, 0xb1, 0x5d, 0x3b, 0x6a, 0xad, 0x8, 0x7c, 0x8b, 0xb8, 0x78, 0xd7, 0x76, 0xf7, 0xc6, 0x41, 0x3b, 0xdc, 0x2b, 0x55, 0xf1, 0xeb, 0xda, 0xe6, 0xe0, 0xfd, 0xf2, 0x2d, 0xbf, 0xb6, 0x7f, 0xd3, 0xe8, 0xf0, 0xb4, 0x98, 0xb1, 0x20, 0x36, 0x14, 0x1b, 0x84, 0x64, 0xcb, 0x1c, 0x36, 0x73, 0x85, 0x58, 0x87, 0x1a, 0xc7, 0x76, 0xfd, 0xa2, 0xfd, 0x21, 0xde, 0xdf, 0xf2, 0x8b, 0x88, 0x8f, 0xb0, 0x23, 0xe7, 0x6c, 0x86, 0xb5, 0x17, 0xb0, 0x1b, 0xa0, 0xf5, 0x68, 0xaf, 0x94, 0xc5, 0xaf, 0x6d, 0xdb, 0x9a, 0xee, 0xcd, 0x83, 0xa6, 0x19, 0x14, 0x68, 0x6c, 0x25, 0xe3, 0xe2, 0x9c, 0xcc, 0x17, 0x35, 0x28, 0xeb, 0x7a, 0xc1, 0x4e, 0x0, 0x2b, 0x87, 0xe8, 0x96, 0xe7, 0x68, 0x82, 0x75, 0xbc, 0x52, 0x96, 0x15, 0x6a, 0x5a, 0xae, 0x5e, 0x81, 0x6e, 0x75, 0xb, 0x2b, 0x63, 0x80, 0xda, 0x96, 0xf7, 0x79, 0x62, 0xdc, 0x2, 0xa7, 0x63, 0x37, 0x33, 0x37, 0xc1, 0xe6, 0x18, 0x3e, 0xad, 0x15, 0x51, 0x7c, 0x3b, 0x87, 0x34, 0xc0, 0xcd, 0x2b, 0x36, 0x6, 0x93, 0x78, 0xa5, 0x2a, 0xa9, 0xba, 0xf6, 0x29, 0xd9, 0x64, 0x1b, 0xdd, 0x3a, 0xe, 0xb4, 0xc5, 0x8f, 0x34, 0x47, 0x3b, 0xfa, 0x4a, 0xa, 0xbf, 0x1b, 0xdf, 0xc4, 0x98, 0x3c, 0xf4, 0xaf, 0x6d, 0x5b, 0x6, 0xff, 0x5e, 0x8a, 0x55, 0xf4, 0x35, 0x36, 0x28, 0x40, 0x27, 0x80, 0x22, 0x2f, 0xa, 0x6d, 0xe, 0xcf, 0x47, 0x3c, 0x69, 0xf7, 0xf0, 0x4a, 0x59, 0xd2, 0xf5, 0x1d, 0x4b, 0x52, 0xe4, 0x4f, 0x29, 0xec, 0x57, 0x14, 0xbd, 0x83, 0x8d, 0x3f, 0xc8, 0xd7, 0xd6, 0x27, 0x31, 0x3f, 0x47, 0x84, 0xff, 0xbc, 0xf8, 0xe6, 0xf0, 0xd5, 0x7c, 0xca, 0xd, 0xe1, 0x46, 0x8d, 0x56, 0xa0, 0xa3, 0x69, 0xb3, 0xec, 0x61, 0xfb, 0x45, 0xf8, 0xb6, 0xb9, 0xf6, 0x28, 0xd2, 0x16, 0xf7, 0x1a, 0xca, 0xe4, 0x65, 0x85, 0x9a, 0xd6, 0x47, 0x39, 0x68, 0x53, 0x94, 0x7a, 0x13, 0x9c, 0xe5, 0xd7, 0xb5, 0xd7, 0xfb, 0xf5, 0x1d, 0x53, 0xf, 0xec, 0x43, 0x64, 0xc7, 0x64, 0x74, 0x76, 0x6f, 0x4a, 0xba, 0x5e, 0x92, 0xa1, 0x52, 0x62, 0xa7, 0x1d, 0x7c, 0x87, 0xb4, 0xad, 0x23, 0x89, 0x8f, 0x77, 0x7d, 0x5c, 0xff, 0x74, 0xd4, 0x5e, 0x22, 0xec, 0x91, 0xc6, 0xe4, 0x3, 0xbe, 0x25, 0xb7, 0x47, 0x7a, 0x15, 0x25, 0xf2, 0x6b, 0xe5, 0xdc, 0x5c, 0x2b, 0x9d, 0xfe, 0xb, 0xd0, 0x8, 0x61, 0x22, 0x55, 0x7f, 0x42, 0xdb, 0x1d, 0xda, 0x22, 0xc6, 0x68, 0x21, 0xca, 0xd7, 0xf5, 0x89, 0x5f, 0xc7, 0x9d, 0x8b, 0x7e, 0xd, 0x77, 0x7e, 0xf0, 0x7b, 0x8a, 0x88, 0x91, 0x27, 0x3, 0x5a, 0xc9, 0x1, 0x9, 0x56, 0xa8, 0x6d, 0x9b, 0xcc, 0xab, 0x44, 0x49, 0xd7, 0x7, 0x17, 0xf3, 0xd9, 0xe0, 0xf3, 0xe2, 0x69, 0xaa, 0x6f, 0x57, 0xa0, 0xab, 0x1d, 0x72, 0xa1, 0xd0, 0xa, 0xad, 0xe1, 0x47, 0xde, 0x6, 0x4e, 0xf3, 0x2a, 0x55, 0x52, 0x75, 0x1d, 0x3b, 0xd2, 0x4, 0xaf, 0xf1, 0xa8, 0xcb, 0xf3, 0x76, 0xa2, 0xcb, 0x1d, 0xee, 0x43, 0xc5, 0xce, 0xc5, 0xc7, 0x2a, 0x6c, 0x2d, 0x7c, 0x4a, 0x3, 0x1c, 0xe6, 0x55, 0xb2, 0xf8, 0x75, 0xc1, 0xec, 0x7c, 0x86, 0x78, 0x51, 0x6e, 0x1e, 0x2, 0xd1, 0x36, 0x81, 0x35, 0x3f, 0x78, 0xe2, 0xd7, 0x8, 0xe2, 0x63, 0x6d, 0x1b, 0xdc, 0x79, 0x50, 0x85, 0x42, 0x82, 0xf6, 0x43, 0x3b, 0xf4, 0x51, 0xc0, 0xb8, 0x5d, 0x45, 0xad, 0x6b, 0x62, 0xb0, 0x8d, 0xbf, 0x2, 0x6d, 0x48, 0xd5, 0xb6, 0x7f, 0x86, 0x6e, 0xf4, 0x2a, 0x5d, 0x32, 0xd, 0xd9, 0x9a, 0x74, 0x43, 0xf0, 0x85, 0x49, 0x18, 0x5a, 0x81, 0x2e, 0x17, 0xd8, 0xb3, 0xbd, 0x5f, 0x55, 0x98, 0x83, 0x71, 0xf0, 0x97, 0xc1, 0xf2, 0x53, 0x72, 0x8f, 0x2e, 0xca, 0x5e, 0x8f, 0x13, 0x6f, 0xf4, 0x97, 0xe4, 0xa5, 0xce, 0xab, 0x6, 0xf1, 0xeb, 0x83, 0xde, 0x74, 0x43, 0x56, 0xa3, 0x35, 0xda, 0x5, 0x2, 0x21, 0x1b, 0x47, 0x7c, 0xbc, 0xd8, 0xf1, 0xd7, 0x5d, 0xb2, 0x36, 0x4a, 0xd0, 0xb2, 0xef, 0xb0, 0xb0, 0x42, 0x61, 0x3e, 0xc8, 0x34, 0xe6, 0x56, 0x46, 0xef, 0xce, 0x29, 0x2e, 0x36, 0x8a, 0x1b, 0x67, 0x8f, 0xa5, 0x71, 0xcc, 0xfc, 0xab, 0xb0, 0xb9, 0x57, 0x2d, 0x42, 0xa7, 0xbf, 0x1, 0xe1, 0xa3, 0xd2, 0xe8, 0x92, 0xa4, 0x71, 0xbc, 0xb1, 0x12, 0x74, 0x61, 0xdf, 0xf2, 0xa8, 0x37, 0xcd, 0x92, 0xa3, 0x78, 0x1b, 0x52, 0xd0, 0x49, 0x3c, 0x11, 0x1a, 0x61, 0x43, 0xae, 0xfd, 0xa, 0xda, 0x8d, 0xb3, 0xc6, 0xf9, 0xfe, 0xf8, 0x6c, 0x2b, 0xfe, 0x19, 0xaf, 0x5a, 0xc4, 0xaf, 0xcf, 0x2e, 0x44, 0xc2, 0xde, 0x4f, 0x87, 0x49, 0xce, 0x29, 0xd0, 0x0, 0xe1, 0xd8, 0x21, 0x5b, 0x20, 0x62, 0xce, 0xbd, 0x1e, 0x45, 0xd6, 0xd6, 0x11, 0x36, 0x38, 0x31, 0xec, 0x51, 0x59, 0xb1, 0x8a, 0x62, 0xcb, 0x7c, 0x0, 0xd9, 0x7, 0x33, 0x8d, 0x9d, 0xab, 0xa5, 0x1b, 0x73, 0x53, 0xa4, 0x9b, 0x7a, 0xfe, 0xe7, 0x39, 0x92, 0x6e, 0xc8, 0x2d, 0xcc, 0x7d, 0x3e, 0x81, 0x9f, 0xac, 0x93, 0x1b, 0x6f, 0x2d, 0x59, 0xff, 0x46, 0xbf, 0x21, 0xbb, 0xa0, 0x57, 0x4d, 0xc2, 0xd, 0x6f, 0xc6, 0x8d, 0x7f, 0x26, 0xd, 0x60, 0x35, 0x41, 0x3c, 0xc4, 0x28, 0xdb, 0x6, 0xfb, 0x9a, 0xd1, 0x23, 0x8e, 0xfd, 0xf8, 0x67, 0xfc, 0x1, 0x45, 0x3f, 0x97, 0xa2, 0x2f, 0xa, 0x53, 0x31, 0xfe, 0xcf, 0xdf, 0xc8, 0xc5, 0x67, 0x16, 0x1a, 0xe1, 0x60, 0xeb, 0xad, 0x4e, 0x89, 0x86, 0xdc, 0xe1, 0xe9, 0xc6, 0xce, 0x99, 0xbc, 0x6a, 0x13, 0x1a, 0xe0, 0x4c, 0x6e, 0xfe, 0x67, 0x93, 0x5c, 0xb4, 0x26, 0xa1, 0x83, 0x82, 0x98, 0x3c, 0xd8, 0x63, 0x83, 0x72, 0xfc, 0x54, 0x41, 0x8b, 0xaf, 0x3b, 0x1f, 0x8b, 0xb3, 0x7e, 0x1f, 0xc5, 0x5a, 0x3c, 0xd3, 0xd4, 0x35, 0x27, 0x7a, 0x1a, 0x6f, 0x10, 0x42, 0xcc, 0x14, 0xc4, 0x2c, 0xc4, 0x1a, 0x9f, 0x81, 0xe6, 0x9, 0xf8, 0x8d, 0xdf, 0x90, 0x5b, 0xdb, 0x97, 0xb7, 0x8c, 0xaa, 0x13, 0x6e, 0xbe, 0x9b, 0x93, 0x91, 0xcf, 0x34, 0x75, 0x6a, 0x50, 0xa2, 0xe3, 0x50, 0x5, 0x88, 0xd5, 0x24, 0xf4, 0x26, 0xd8, 0x1f, 0xee, 0x66, 0xfc, 0x17, 0xe8, 0x28, 0xec, 0x78, 0x6b, 0x1c, 0xb, 0xbe, 0xca, 0xb2, 0xff, 0xf1, 0x86, 0x29, 0x34, 0xc2, 0x42, 0xec, 0x77, 0x7, 0x58, 0xd2, 0xab, 0x66, 0x21, 0x1, 0x5f, 0x83, 0x26, 0x21, 0xa, 0xb4, 0xd8, 0x91, 0x70, 0xdd, 0x1d, 0xbf, 0x97, 0x6e, 0xec, 0x4a, 0xc1, 0xc4, 0x8c, 0xe7, 0xce, 0x34, 0x75, 0xa7, 0x60, 0x4d, 0xc6, 0xeb, 0xc3, 0x26, 0xb0, 0x23, 0x1c, 0x83, 0xdf, 0xb5, 0x70, 0x3f, 0x3c, 0xb, 0xda, 0x7e, 0xcd, 0x81, 0x42, 0x8c, 0x2, 0x4d, 0xd3, 0xfe, 0x63, 0x5e, 0xcf, 0x1b, 0xa6, 0xac, 0x74, 0x48, 0x2f, 0x6b, 0x54, 0xb9, 0x64, 0x1a, 0xbb, 0x2e, 0xee, 0x2f, 0x8, 0x49, 0x86, 0x15, 0xad, 0xa2, 0x60, 0xbb, 0x28, 0x8, 0xfd, 0xf0, 0x57, 0x60, 0xfc, 0xb6, 0x49, 0xd5, 0x65, 0x23, 0xdf, 0x7b, 0xcd, 0x7, 0x32, 0x7c, 0xa6, 0x85, 0x39, 0x61, 0x3e, 0xe0, 0x4b, 0xb3, 0xce, 0x3e, 0x7b, 0x2d, 0x74, 0x2c, 0xe2, 0xab, 0x88, 0xd5, 0xd0, 0x37, 0x12, 0xd, 0x90, 0x8, 0x42, 0x22, 0xe7, 0xe2, 0xc4, 0x6e, 0x4b, 0x13, 0x3c, 0x16, 0x16, 0xfd, 0xe0, 0xee, 0x2, 0xca, 0x1a, 0x2b, 0x6b, 0xac, 0xc, 0x72, 0x8a, 0xcf, 0x26, 0x7e, 0xf2, 0x41, 0xbe, 0xde, 0xc4, 0x14, 0xb2, 0x93, 0xb5, 0xf2, 0xb2, 0x5e, 0x34, 0x4d, 0xe0, 0xec, 0x47, 0xf8, 0x91, 0x3d, 0x27, 0xd, 0x30, 0xc2, 0x8d, 0xb0, 0x14, 0x49, 0xdd, 0x1b, 0x9e, 0x0, 0xd, 0x24, 0xbd, 0xc7, 0xa0, 0x84, 0xd0, 0x66, 0xde, 0xa0, 0xe1, 0x29, 0x62, 0x66, 0xf6, 0x6, 0x29, 0xac, 0x31, 0x9, 0xd4, 0x12, 0x3b, 0x4e, 0x5e, 0x43, 0xd6, 0x8e, 0xc7, 0xf8, 0x13, 0x97, 0x47, 0xbf, 0x4, 0x13, 0x79, 0xa3, 0x22, 0x49, 0x23, 0x2c, 0xb, 0xfb, 0x92, 0xe0, 0xdb, 0xe0, 0x67, 0xd0, 0x16, 0x4a, 0x8a, 0xf0, 0x3d, 0xac, 0x31, 0xf4, 0xf, 0x60, 0x3d, 0x73, 0x11, 0xaf, 0xad, 0x6, 0x80, 0x81, 0x35, 0x0, 0xfc, 0x43, 0xec, 0x9d, 0xf0, 0x7f, 0x6f, 0xf4, 0x24, 0x91, 0x74, 0x53, 0xf7, 0x1c, 0xb0, 0x3f, 0x9c, 0x43, 0xc1, 0x3a, 0x40, 0x67, 0x28, 0x2, 0xfa, 0x77, 0xe6, 0xf6, 0x1e, 0x81, 0xf5, 0x3b, 0x56, 0x3c, 0xb8, 0xb7, 0xf, 0x58, 0x93, 0x2, 0x1f, 0xd2, 0x4b, 0x91, 0x5, 0x6c, 0x1b, 0xae, 0x2b, 0x33, 0x2f, 0xfc, 0x49, 0xec, 0xd1, 0x90, 0x34, 0xc0, 0x58, 0x9, 0x45, 0xf0, 0xe1, 0x42, 0xb8, 0x1e, 0x4e, 0x1e, 0x89, 0x5f, 0x48, 0xa1, 0x80, 0x1b, 0xd2, 0x50, 0x7f, 0x80, 0x29, 0xb2, 0x12, 0xb4, 0x8c, 0x6d, 0x94, 0xc1, 0xcc, 0xb, 0x79, 0xd8, 0x4c, 0xfe, 0x34, 0xbd, 0x5c, 0x25, 0x11, 0x9a, 0xc0, 0x7c, 0xcb, 0xf6, 0x33, 0xb4, 0xa6, 0x98, 0xe3, 0xc1, 0xdc, 0x4, 0xc1, 0xff, 0x53, 0x74, 0x2b, 0x3e, 0x73, 0x7b, 0xe5, 0x2f, 0x89, 0xf0, 0x68, 0x3f, 0x8b, 0xd3, 0xdd, 0x27, 0x8f, 0x7f, 0x85, 0xfe, 0x1b, 0x7e, 0xc6, 0xfe, 0x1a, 0xfd, 0x21, 0xbc, 0xcc, 0x69, 0xf, 0xd0, 0xf, 0x33, 0x77, 0x2b, 0xf6, 0xfe, 0x2b, 0x1d, 0xfa, 0xe4, 0xd2, 0x5e, 0x65, 0x48, 0x22, 0x9c, 0xe4, 0xa9, 0x38, 0xd1, 0x77, 0xc2, 0x43, 0xd8, 0x77, 0xc0, 0x35, 0x70, 0x16, 0xff, 0x60, 0xf9, 0x70, 0xd8, 0x3, 0x7b, 0xd, 0xae, 0xcd, 0xe2, 0x95, 0xbd, 0x24, 0x92, 0x48, 0x22, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89, 0xfc, 0xb, 0x31, 0x1b, 0x93, 0xfa, 0xac, 0xe1, 0x98, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char mini_checkerboard_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x7c, 0xf0, 0xe0, 0xc1, 0x7f, 0x6, 0x3c, 0x40, 0x5e, 0x5e, 0x1e, 0x9f, 0x34, 0x3, 0x13, 0x5e, 0x59, 0x22, 0xc0, 0xa8, 0x1, 0x83, 0xc1, 0x0, 0xc6, 0xff, 0xff, 0xff, 0xe3, 0x4d, 0x7, 0xf, 0x1f, 0x3e, 0xa4, 0xad, 0xb, 0x46, 0xd, 0x18, 0xc, 0x6, 0x0, 0x0, 0x6e, 0x41, 0xa, 0xba, 0x94, 0xaa, 0x47, 0x57, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x98, 0xa0, 0xbd, 0x0, 0x0, 0x0, 0x17, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0x0, 0x5, 0xff, 0xa1, 0x60, 0xa0, 0x4, 0x60, 0xc, 0x98, 0xc4, 0x0, 0x9, 0x0, 0x0, 0x44, 0x81, 0xef, 0x81, 0xc1, 0x26, 0x8e, 0x8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_arrow_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x98, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xbd, 0x91, 0xb1, 0xd, 0xc2, 0x30, 0x10, 0x45, 0xdf, 0xd1, 0xb8, 0xf0, 0x2, 0xee, 0xdc, 0x87, 0x1, 0xd8, 0x24, 0xb5, 0xe9, 0x19, 0x87, 0x1e, 0xea, 0x6c, 0xc2, 0x0, 0xa4, 0xb5, 0xdc, 0x79, 0x1, 0x17, 0xae, 0x8e, 0x26, 0x48, 0x76, 0x14, 0x40, 0x48, 0x88, 0xdf, 0xfd, 0xf7, 0xef, 0x4b, 0x77, 0x3a, 0xf8, 0x85, 0x62, 0x8c, 0x21, 0xc6, 0x18, 0xb6, 0x32, 0x59, 0x83, 0x94, 0xd2, 0x5e, 0x55, 0x6f, 0x0, 0x22, 0x72, 0xf0, 0xde, 0xdf, 0xdb, 0x7c, 0xd7, 0x9a, 0x9c, 0xb3, 0x55, 0xd5, 0x9, 0xb0, 0x80, 0x55, 0xd5, 0x29, 0xe7, 0x6c, 0x5f, 0x16, 0x6a, 0xad, 0x67, 0x60, 0x68, 0xd0, 0xb0, 0xb0, 0x3f, 0xaa, 0x3b, 0x3a, 0xa5, 0x74, 0x51, 0xd5, 0xd0, 0xd, 0x88, 0x5c, 0xbd, 0xf7, 0xc7, 0xa7, 0xef, 0x6e, 0x30, 0xc6, 0x9c, 0x80, 0xb9, 0x41, 0xf3, 0xc2, 0xd8, 0x2c, 0x38, 0xe7, 0x8a, 0x88, 0x8c, 0x40, 0x1, 0x8a, 0x88, 0x8c, 0xce, 0xb9, 0xf2, 0x71, 0xcf, 0x77, 0x8f, 0xfb, 0x5a, 0xf, 0x28, 0x4a, 0x37, 0xff, 0x58, 0x46, 0x7b, 0x50, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x2, 0xdc, 0x4f, 0xb8, 0x9f, 0x80, 0x45, 0xf8, 0xa1, 0xf6, 0x83, 0x2f, 0xf, 0xbe, 0x3c, 0xd4, 0x46, 0x13, 0x7e, 0xc1, 0xfd, 0xe0, 0xea, 0x83, 0xff, 0x40, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xfa, 0xf9, 0x40, 0x41, 0x30, 0x7c, 0x38, 0x9f, 0x81, 0x12, 0x80, 0x69, 0x14, 0x61, 0xcb, 0x11, 0xce, 0xc5, 0xe5, 0x41, 0xc2, 0x0, 0x0, 0x95, 0x48, 0x37, 0x91, 0x1f, 0xec, 0x77, 0x5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_button_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x32, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3f, 0x3f, 0x5a, 0x5a, 0x5a, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x59, 0x59, 0x59, 0x2a, 0x2a, 0x30, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x27, 0x35, 0x35, 0x35, 0x4a, 0x4a, 0x4a, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x56, 0x56, 0x56, 0x62, 0x62, 0x62, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x48, 0x48, 0x48, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x54, 0x54, 0x54, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x49, 0x49, 0x49, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x39, 0x39, 0x39, 0x47, 0x47, 0x47, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x46, 0x46, 0x46, 0xff, 0xff, 0xff, 0xbd, 0x3f, 0x83, 0xbb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x65, 0xb5, 0xdd, 0x88, 0x9f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0xb, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0xd9, 0x56, 0xc2, 0x30, 0x10, 0x80, 0x61, 0xd6, 0xa2, 0xa8, 0x6c, 0x75, 0xdf, 0x10, 0x54, 0xa8, 0x82, 0x74, 0xd2, 0x4a, 0x49, 0x5b, 0xa4, 0xb5, 0x5a, 0x44, 0x10, 0x5c, 0xd0, 0xaa, 0x80, 0x8a, 0xcb, 0xfb, 0x3f, 0x83, 0x21, 0x24, 0x1c, 0x8e, 0x5e, 0xe8, 0x77, 0xfd, 0x9f, 0x93, 0x99, 0x89, 0xcf, 0x1f, 0x8, 0x86, 0xc2, 0x42, 0x84, 0x10, 0x66, 0x66, 0xa3, 0x73, 0xf3, 0xbe, 0x9f, 0x2, 0xb, 0xb1, 0x78, 0x22, 0x99, 0x12, 0x45, 0x71, 0x71, 0x69, 0x79, 0x25, 0xea, 0xff, 0x15, 0x4, 0x63, 0xab, 0x6b, 0x7b, 0xcc, 0x7e, 0x2e, 0x2f, 0x1d, 0x30, 0x87, 0x52, 0x21, 0xbf, 0xbe, 0x41, 0x82, 0x50, 0x7c, 0xb3, 0x78, 0x54, 0x1a, 0x93, 0x1, 0x29, 0x2a, 0x73, 0xac, 0x94, 0x35, 0x6d, 0x8b, 0x4, 0xe1, 0x84, 0x5c, 0xe2, 0xe4, 0xa, 0xd6, 0xb, 0x8c, 0xa1, 0x2b, 0xd8, 0x54, 0x48, 0x20, 0x24, 0xab, 0x27, 0x5c, 0xb5, 0x2, 0x39, 0x89, 0xa9, 0x19, 0x2a, 0x58, 0xa3, 0x20, 0x92, 0xb2, 0x4f, 0x39, 0xdb, 0x1, 0xe3, 0x8c, 0xa9, 0x9d, 0xbb, 0x60, 0x3a, 0xa3, 0x40, 0xac, 0x5f, 0x70, 0xf5, 0xe9, 0xc0, 0x20, 0x1, 0xd0, 0xa0, 0x71, 0xc9, 0x35, 0xca, 0x4d, 0x75, 0x6a, 0x86, 0xd6, 0x15, 0xa6, 0x4f, 0xb4, 0x3b, 0x5c, 0x1b, 0xa1, 0xeb, 0x1b, 0x46, 0xbf, 0x5, 0xed, 0xe, 0xd1, 0x21, 0xbb, 0xf7, 0x5c, 0xf7, 0xc1, 0xf2, 0x26, 0x6b, 0x7a, 0x4d, 0xeb, 0xd1, 0xa2, 0x6b, 0x3e, 0x3d, 0x73, 0xc5, 0x5e, 0x1f, 0x7b, 0xc, 0xe0, 0xc1, 0xcb, 0xab, 0x49, 0xf, 0xb5, 0xdd, 0x79, 0x63, 0x86, 0xbd, 0x77, 0xd, 0x33, 0xad, 0x41, 0xff, 0xe3, 0x33, 0x4d, 0x4f, 0xbd, 0x93, 0x19, 0x7e, 0x8d, 0xd9, 0x0, 0xee, 0x64, 0x6, 0xd7, 0x41, 0xd9, 0xdd, 0xff, 0x7c, 0xd6, 0x5f, 0xdf, 0xfd, 0xd, 0xbf, 0xaa, 0x55, 0xdf, 0x7c, 0xb2, 0x44, 0x90, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x2f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3f, 0x3f, 0x5a, 0x5a, 0x5a, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x59, 0x59, 0x59, 0x2a, 0x2a, 0x30, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x27, 0x35, 0x35, 0x35, 0x4a, 0x4a, 0x4a, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x56, 0x56, 0x56, 0x62, 0x62, 0x62, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x48, 0x48, 0x48, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x54, 0x54, 0x54, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x49, 0x49, 0x49, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x39, 0x39, 0x39, 0x47, 0x47, 0x47, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x46, 0x46, 0x46, 0xd3, 0xa7, 0xd4, 0x88, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xec, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x8e, 0x5, 0x4e, 0x0, 0x31, 0x10, 0x45, 0xff, 0xef, 0x56, 0xc2, 0xe2, 0xee, 0x4e, 0x3c, 0xc8, 0xd, 0xb8, 0x38, 0xa7, 0xc0, 0xdd, 0xdd, 0x5d, 0xbb, 0x94, 0x4c, 0xd2, 0xc1, 0xdf, 0x4a, 0x47, 0x5e, 0x27, 0xc3, 0xc, 0x80, 0x64, 0x24, 0xb8, 0xc7, 0x4f, 0x2c, 0x6b, 0xd5, 0x90, 0xff, 0xdd, 0x23, 0x7e, 0xc1, 0xa2, 0xb6, 0x64, 0xad, 0x26, 0x82, 0xc6, 0xef, 0x45, 0xbc, 0xe3, 0x1, 0x2c, 0x69, 0x9b, 0xc8, 0x7f, 0x5, 0x36, 0x1e, 0x41, 0x84, 0xd6, 0x4, 0x25, 0x90, 0xb7, 0x39, 0x6c, 0x4c, 0x2f, 0xbe, 0x68, 0xdf, 0x13, 0xa1, 0x9e, 0xc8, 0xa4, 0xb7, 0xe7, 0x47, 0x93, 0x63, 0x1b, 0xf9, 0xdc, 0x8, 0x88, 0x60, 0xbf, 0x4, 0xff, 0xd2, 0x56, 0x93, 0xe3, 0xb7, 0xb2, 0xf6, 0x2c, 0x36, 0x1, 0x16, 0xf4, 0x5f, 0x42, 0xc4, 0x17, 0x8f, 0xb5, 0xc0, 0xa5, 0x8, 0x30, 0x5f, 0xc2, 0x5d, 0xcf, 0xc9, 0xd, 0x74, 0x87, 0x8b, 0x5e, 0x56, 0x22, 0x24, 0xf7, 0x6d, 0xc2, 0xd1, 0x80, 0x26, 0x27, 0x5d, 0x5b, 0x67, 0x7d, 0x2f, 0x80, 0x4d, 0xc9, 0x7f, 0x9, 0x63, 0xa7, 0x61, 0x23, 0xc7, 0x74, 0x3d, 0xf, 0xae, 0x41, 0x84, 0x6f, 0x13, 0xe6, 0x26, 0xfa, 0x36, 0x46, 0x73, 0xbc, 0xba, 0x3b, 0xd6, 0xca, 0x8, 0xd0, 0xd6, 0x36, 0x4e, 0x35, 0xeb, 0xad, 0xd7, 0xb0, 0x60, 0x72, 0xdc, 0xda, 0x9c, 0x2, 0x67, 0x76, 0x64, 0x82, 0x99, 0x9b, 0xb6, 0x80, 0xb0, 0x7e, 0x8d, 0xf6, 0x5a, 0xdd, 0xe1, 0xb5, 0xba, 0xba, 0xb1, 0x0, 0xcd, 0xc7, 0x50, 0x23, 0xeb, 0xfb, 0x7f, 0xb4, 0xc8, 0x22, 0x18, 0xdd, 0x0, 0xd5, 0xec, 0x4e, 0x53, 0xc6, 0x18, 0x44, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_button_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xb4, 0x50, 0x4c, 0x54, 0x45, 0x95, 0xa9, 0xb0, 0x92, 0xa7, 0xae, 0x8e, 0xa2, 0xa9, 0x8a, 0x9d, 0xa4, 0x85, 0x98, 0x9f, 0x80, 0x93, 0x9b, 0x7b, 0x8f, 0x96, 0x77, 0x8a, 0x92, 0x72, 0x86, 0x8c, 0x6e, 0x80, 0x88, 0x69, 0x7c, 0x84, 0x64, 0x77, 0x7f, 0x60, 0x72, 0x7a, 0x5b, 0x6e, 0x75, 0x56, 0x69, 0x71, 0xc8, 0xe3, 0xe7, 0xc8, 0xe2, 0xe7, 0xca, 0xe3, 0xe7, 0xce, 0xe6, 0xe9, 0xce, 0xe6, 0xea, 0xd0, 0xe6, 0xe9, 0xce, 0xe5, 0xea, 0xd0, 0xe6, 0xea, 0xce, 0xe5, 0xe9, 0xd0, 0xe5, 0xe9, 0xd3, 0xe7, 0xeb, 0xd4, 0xe7, 0xeb, 0xd9, 0xea, 0xed, 0xd7, 0xe9, 0xed, 0xd7, 0xea, 0xed, 0xdc, 0xec, 0xef, 0xdc, 0xeb, 0xef, 0xe0, 0xed, 0xf1, 0xdf, 0xee, 0xf1, 0xdf, 0xed, 0xf1, 0xe0, 0xee, 0xf1, 0xe3, 0xf0, 0xf2, 0xe2, 0xef, 0xf2, 0xe3, 0xef, 0xf2, 0xe6, 0xf1, 0xf3, 0xe8, 0xf2, 0xf5, 0xe8, 0xf3, 0xf4, 0xe8, 0xf2, 0xf4, 0xe8, 0xf3, 0xf5, 0xd6, 0x5a, 0x5b, 0xd4, 0x57, 0x58, 0xe5, 0x89, 0x89, 0xd5, 0x57, 0x59, 0xd5, 0x58, 0x59, 0xd5, 0x59, 0x5a, 0xd6, 0x59, 0x5a, 0xd6, 0x5a, 0x5c, 0xd7, 0x5b, 0x5c, 0xd7, 0x5b, 0x5d, 0xd8, 0x5c, 0x5d, 0xd8, 0x5c, 0x5e, 0xd8, 0x5d, 0x5f, 0xd9, 0x5d, 0x5f, 0xe8, 0x6c, 0x6e, 0xff, 0xff, 0xff, 0xa1, 0xe, 0x37, 0x8c, 0x0, 0x0, 0x0, 0x2c, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xac, 0x80, 0x68, 0x47, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x3b, 0x39, 0xe, 0xf4, 0x6c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xa3, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x5d, 0xce, 0xdb, 0x16, 0x42, 0x60, 0x18, 0x84, 0xe1, 0x4f, 0x8, 0x65, 0x57, 0x2a, 0x45, 0xd9, 0x15, 0xf9, 0xa3, 0x89, 0x28, 0xea, 0xfe, 0x2f, 0x2c, 0x4e, 0x2c, 0x79, 0xd6, 0xbc, 0xe7, 0x43, 0x34, 0xc5, 0xe5, 0x7f, 0x38, 0x9a, 0xdd, 0x31, 0x72, 0x9f, 0x11, 0xff, 0x80, 0x61, 0x18, 0xa6, 0x69, 0xac, 0xba, 0x50, 0xf0, 0x24, 0x14, 0x58, 0x5b, 0x9b, 0xed, 0xce, 0xb6, 0x6d, 0x6b, 0x8f, 0x42, 0x20, 0xb1, 0xc4, 0xc1, 0x71, 0xe, 0x7d, 0x8e, 0x83, 0x52, 0xa4, 0xf9, 0x13, 0xae, 0x7b, 0x74, 0x7b, 0xa7, 0x13, 0x9e, 0x73, 0x92, 0x72, 0x78, 0xbe, 0xef, 0x75, 0x7c, 0xcf, 0x47, 0x2e, 0x91, 0x5c, 0x21, 0x8, 0xc2, 0x20, 0x8c, 0x82, 0x73, 0x18, 0xa1, 0x92, 0x49, 0xa9, 0x71, 0x89, 0xe3, 0x38, 0x49, 0xba, 0x25, 0xa8, 0x15, 0x5a, 0xbc, 0x70, 0x1d, 0xe0, 0xb5, 0xa0, 0xe5, 0x1b, 0x69, 0xca, 0xd8, 0x8d, 0x31, 0x96, 0x65, 0x68, 0x96, 0xa4, 0x36, 0x60, 0x3, 0x34, 0x2a, 0x69, 0xed, 0xf8, 0x7a, 0xab, 0x91, 0xfe, 0xf9, 0x8e, 0x7c, 0x74, 0xd2, 0x27, 0x7e, 0x7e, 0x46, 0x20, 0x17, 0xe, 0x2d, 0x4e, 0x9, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xb1, 0x50, 0x4c, 0x54, 0x45, 0x95, 0xa9, 0xb0, 0x92, 0xa7, 0xae, 0x8e, 0xa2, 0xa9, 0x8a, 0x9d, 0xa4, 0x85, 0x98, 0x9f, 0x80, 0x93, 0x9b, 0x7b, 0x8f, 0x96, 0x77, 0x8a, 0x92, 0x72, 0x86, 0x8c, 0x6e, 0x80, 0x88, 0x69, 0x7c, 0x84, 0x64, 0x77, 0x7f, 0x60, 0x72, 0x7a, 0x5b, 0x6e, 0x75, 0x56, 0x69, 0x71, 0xc8, 0xe3, 0xe7, 0xc8, 0xe2, 0xe7, 0xca, 0xe3, 0xe7, 0xce, 0xe6, 0xe9, 0xce, 0xe6, 0xea, 0xd0, 0xe6, 0xe9, 0xce, 0xe5, 0xea, 0xd0, 0xe6, 0xea, 0xce, 0xe5, 0xe9, 0xd0, 0xe5, 0xe9, 0xd3, 0xe7, 0xeb, 0xd4, 0xe7, 0xeb, 0xd9, 0xea, 0xed, 0xd7, 0xe9, 0xed, 0xd7, 0xea, 0xed, 0xdc, 0xec, 0xef, 0xdc, 0xeb, 0xef, 0xe0, 0xed, 0xf1, 0xdf, 0xee, 0xf1, 0xdf, 0xed, 0xf1, 0xe0, 0xee, 0xf1, 0xe3, 0xf0, 0xf2, 0xe2, 0xef, 0xf2, 0xe3, 0xef, 0xf2, 0xe6, 0xf1, 0xf3, 0xe8, 0xf2, 0xf5, 0xe8, 0xf3, 0xf4, 0xe8, 0xf2, 0xf4, 0xe8, 0xf3, 0xf5, 0xd6, 0x5a, 0x5b, 0xd4, 0x57, 0x58, 0xe5, 0x89, 0x89, 0xd5, 0x57, 0x59, 0xd5, 0x58, 0x59, 0xd5, 0x59, 0x5a, 0xd6, 0x59, 0x5a, 0xd6, 0x5a, 0x5c, 0xd7, 0x5b, 0x5c, 0xd7, 0x5b, 0x5d, 0xd8, 0x5c, 0x5d, 0xd8, 0x5c, 0x5e, 0xd8, 0x5d, 0x5f, 0xd9, 0x5d, 0x5f, 0xe8, 0x6c, 0x6e, 0x20, 0x6, 0x32, 0x78, 0x0, 0x0, 0x0, 0x2c, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xac, 0x80, 0x68, 0x47, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xc8, 0xc1, 0x8d, 0xc2, 0x30, 0x18, 0x6, 0xd1, 0x99, 0xdf, 0x8e, 0x7c, 0x59, 0x6d, 0xb, 0x14, 0x40, 0xff, 0xa5, 0x50, 0x0, 0x6d, 0x4, 0xe4, 0xf, 0x59, 0x8, 0x42, 0xde, 0xf1, 0x35, 0xce, 0xd0, 0x2b, 0xbf, 0x6e, 0x5d, 0xe5, 0x10, 0xbb, 0x95, 0x3b, 0x48, 0x2a, 0xe4, 0xd2, 0xec, 0x9a, 0xe6, 0x2, 0xcf, 0xd, 0x56, 0x30, 0x24, 0x48, 0x6, 0xb8, 0x82, 0xc2, 0x0, 0xd6, 0x3b, 0xf6, 0x6a, 0x12, 0xc0, 0xc8, 0x6e, 0x77, 0x3c, 0xa, 0xa3, 0xb3, 0x4d, 0x19, 0x76, 0xa5, 0xb, 0x12, 0x1b, 0xb8, 0x82, 0xc6, 0x22, 0x7c, 0x42, 0xc4, 0x40, 0x41, 0x59, 0x8a, 0x42, 0x80, 0x39, 0xc1, 0xae, 0x6c, 0x7c, 0xb9, 0xe2, 0x8f, 0x43, 0xf4, 0x9f, 0xb3, 0x17, 0x98, 0xa8, 0x1a, 0xb6, 0xa7, 0xd9, 0xa6, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_button_hover_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x44, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x5f, 0x5a, 0x6b, 0x2a, 0x2a, 0x30, 0x56, 0x53, 0x64, 0x22, 0x22, 0x27, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x67, 0x63, 0x76, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5a, 0x56, 0x65, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x5b, 0x57, 0x66, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x43, 0x40, 0x4c, 0x54, 0x50, 0x5f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x4f, 0x5f, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x5f, 0x5a, 0x6c, 0xff, 0xff, 0xff, 0xd1, 0x85, 0xc5, 0x5, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6b, 0x52, 0x65, 0xa5, 0x98, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0x10, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0x61, 0xd6, 0xa2, 0xa8, 0x6c, 0x75, 0xdf, 0x77, 0xa8, 0xa2, 0x70, 0xd2, 0x4a, 0x25, 0x6d, 0x81, 0x62, 0xa1, 0x88, 0x20, 0x6e, 0xc5, 0xaa, 0x80, 0xfb, 0xfa, 0xfe, 0xf, 0x60, 0x49, 0x13, 0x86, 0xd1, 0xb, 0xfd, 0x6e, 0xf3, 0xcf, 0xe4, 0x24, 0xc7, 0xe3, 0xf5, 0xf9, 0x3, 0x41, 0x2e, 0xe4, 0xe0, 0x46, 0x46, 0xc3, 0x63, 0xe3, 0x9e, 0x9f, 0x7c, 0x13, 0x91, 0x68, 0x2c, 0x9e, 0xe0, 0x79, 0x7e, 0x72, 0x6a, 0x7a, 0x26, 0xec, 0xfd, 0x15, 0xf8, 0x23, 0xb3, 0x73, 0x9b, 0x5b, 0xae, 0xed, 0x64, 0x4a, 0xd8, 0xa1, 0x76, 0x85, 0x74, 0x6a, 0x7e, 0xc1, 0x9, 0x2, 0xd1, 0xc5, 0xbd, 0xfd, 0x8c, 0x2b, 0xb, 0x48, 0x94, 0xa8, 0x3, 0x31, 0x27, 0xcb, 0x4b, 0x4e, 0x10, 0x8c, 0x1d, 0xb2, 0xf3, 0x4c, 0x36, 0x8f, 0x95, 0x34, 0xa5, 0x2a, 0x22, 0xd6, 0x44, 0x27, 0xe0, 0xe2, 0x85, 0x22, 0x53, 0xc8, 0x43, 0x52, 0xa0, 0x4a, 0xaa, 0x4, 0x7a, 0x3f, 0x8, 0x25, 0xca, 0x47, 0x4c, 0xd9, 0x0, 0xb5, 0x42, 0x95, 0xaa, 0x26, 0x68, 0x46, 0x3f, 0xe0, 0x6b, 0xc7, 0x4c, 0x6d, 0x38, 0x50, 0x9d, 0x0, 0x48, 0x50, 0x3f, 0x61, 0xea, 0xb9, 0x86, 0x34, 0x34, 0x43, 0xf3, 0x14, 0x93, 0x2b, 0x5a, 0x67, 0x4c, 0xb, 0xa1, 0xf3, 0xb, 0x4a, 0xb9, 0x4, 0xf9, 0xa, 0x91, 0x21, 0xad, 0x36, 0x63, 0x5d, 0xeb, 0xf6, 0xe0, 0x99, 0x76, 0x43, 0xbf, 0xd1, 0xc9, 0x33, 0xad, 0xf6, 0x2d, 0x75, 0xd7, 0xe9, 0x62, 0x9b, 0x2, 0xdc, 0xbb, 0x7f, 0xd0, 0xc8, 0x47, 0x2d, 0x3f, 0x3e, 0x3d, 0xbb, 0x5e, 0x3a, 0xaf, 0x32, 0xa6, 0x9a, 0xbd, 0xee, 0xdb, 0xfb, 0xa, 0xf9, 0xea, 0xd5, 0xb5, 0x8f, 0x4f, 0xd7, 0x17, 0x80, 0x39, 0x98, 0xc1, 0x34, 0xd0, 0xfa, 0xc6, 0x7f, 0x96, 0xf5, 0xd7, 0xba, 0xbf, 0x1, 0xfe, 0x22, 0x58, 0x7c, 0xf4, 0xd2, 0xd1, 0x68, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x5f, 0x5a, 0x6b, 0x2a, 0x2a, 0x30, 0x56, 0x53, 0x64, 0x22, 0x22, 0x27, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x67, 0x63, 0x76, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5a, 0x56, 0x65, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x5b, 0x57, 0x66, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x43, 0x40, 0x4c, 0x54, 0x50, 0x5f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x4f, 0x5f, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x5f, 0x5a, 0x6c, 0xd3, 0x26, 0x54, 0x35, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe5, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x91, 0x43, 0x62, 0xc5, 0x60, 0x18, 0x45, 0xef, 0x8d, 0x51, 0xdb, 0xee, 0x46, 0xca, 0x6d, 0x77, 0x58, 0xce, 0x6b, 0xdb, 0x7c, 0x8a, 0xad, 0xea, 0x44, 0x1f, 0x4e, 0x92, 0x1f, 0x4c, 0x0, 0xe0, 0x9, 0x61, 0xf0, 0x89, 0x32, 0x12, 0xcd, 0xd4, 0x8, 0xef, 0x1f, 0x35, 0x54, 0xa0, 0x68, 0x1a, 0x34, 0x89, 0x8, 0x86, 0xa4, 0xd, 0x57, 0xb4, 0xdf, 0x79, 0x5, 0x89, 0x94, 0xba, 0xf9, 0xb3, 0xc0, 0xce, 0xeb, 0xf0, 0x17, 0x1c, 0xab, 0x11, 0x9, 0x1a, 0xf9, 0x96, 0x84, 0x5d, 0x5e, 0x43, 0x15, 0x7, 0x2e, 0x42, 0x41, 0x51, 0xd3, 0xbe, 0x67, 0xd5, 0x6b, 0x42, 0x3a, 0x38, 0x9b, 0xf5, 0x2e, 0x20, 0xfa, 0x5, 0x33, 0x41, 0x69, 0xf4, 0xeb, 0x49, 0x6c, 0x19, 0xe6, 0xbd, 0xdd, 0xd, 0x48, 0xa0, 0x92, 0xb, 0x36, 0x72, 0x6a, 0x26, 0xf0, 0x14, 0xa, 0x10, 0x72, 0xe1, 0x7d, 0xf4, 0xf6, 0x35, 0x1b, 0xc3, 0xe3, 0x18, 0x9d, 0x50, 0xf0, 0xe4, 0xc2, 0x17, 0xae, 0x27, 0xd3, 0xe4, 0x6e, 0xe8, 0xf8, 0x7e, 0xbc, 0x1, 0x48, 0x9e, 0x57, 0xf8, 0xc5, 0xfc, 0xbd, 0x7a, 0x98, 0xc4, 0x94, 0x47, 0xbf, 0xe4, 0xce, 0x48, 0x8, 0x6e, 0x69, 0x91, 0x63, 0x47, 0x73, 0x49, 0xbc, 0x77, 0x3e, 0xd7, 0x4b, 0x3b, 0x12, 0x36, 0x16, 0xb3, 0x85, 0x6a, 0x68, 0xce, 0x39, 0x62, 0xc6, 0xba, 0x3d, 0x8d, 0xe7, 0x91, 0x20, 0xac, 0xad, 0xa6, 0xc2, 0xe, 0x6, 0xcc, 0x74, 0xc, 0x2d, 0xe7, 0xf9, 0x55, 0x2, 0x28, 0x94, 0x37, 0xab, 0xee, 0xa1, 0xcc, 0xbf, 0xdb, 0xed, 0x3, 0x70, 0xe6, 0x4f, 0x4a, 0xc3, 0xed, 0xed, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_button_normal_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x44, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0xff, 0xff, 0xff, 0xd7, 0xc8, 0xfe, 0x88, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6b, 0x52, 0x65, 0xa5, 0x98, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x1, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0xd7, 0x56, 0xc2, 0x40, 0x10, 0x80, 0x61, 0x6a, 0x50, 0x54, 0x5a, 0xec, 0xbd, 0x43, 0x14, 0x85, 0xdd, 0x44, 0xa2, 0x6c, 0x12, 0x20, 0x18, 0xd, 0x22, 0x8, 0x16, 0x34, 0x16, 0xc0, 0x5e, 0xde, 0xff, 0x1, 0x5c, 0x36, 0xb3, 0x1c, 0x8e, 0x5e, 0xe8, 0x77, 0xfd, 0x9f, 0xb3, 0x33, 0xb3, 0x1e, 0xaf, 0xcf, 0x1f, 0x8, 0xa, 0x21, 0x4a, 0x18, 0x1a, 0xe, 0x8f, 0x8c, 0x7a, 0x7e, 0xf2, 0x8d, 0x45, 0xa2, 0xb1, 0x78, 0x42, 0x14, 0xc5, 0xf1, 0x89, 0xc9, 0xa9, 0xb0, 0xf7, 0x57, 0xe0, 0x8f, 0x4c, 0xcf, 0xac, 0x6f, 0xb8, 0x36, 0x93, 0x29, 0x69, 0xb, 0x6c, 0x4b, 0xe9, 0xd4, 0xec, 0x1c, 0xd, 0x2, 0xd1, 0xf9, 0x9d, 0xdd, 0x8c, 0x2b, 0x8b, 0xb0, 0xac, 0x80, 0x3d, 0x39, 0xa7, 0xaa, 0xb, 0x34, 0x8, 0xc6, 0xb2, 0x99, 0x7d, 0x70, 0x90, 0x27, 0x5a, 0x1a, 0xe8, 0x9a, 0x4c, 0xc, 0x99, 0x6, 0x42, 0xbc, 0x50, 0xe4, 0xa, 0x79, 0x94, 0x94, 0x40, 0x49, 0x57, 0x90, 0xd9, 0xb, 0x42, 0x89, 0xf2, 0x21, 0x57, 0xb6, 0x90, 0x7e, 0x4, 0x4a, 0xc7, 0x36, 0x32, 0xac, 0x5e, 0x20, 0x56, 0x4e, 0xb8, 0xca, 0x60, 0xa0, 0xd3, 0x0, 0xb1, 0xa0, 0x7a, 0xca, 0x55, 0x73, 0x35, 0x65, 0x60, 0x86, 0xfa, 0x19, 0x61, 0x4f, 0x34, 0x9a, 0x5c, 0x3, 0xe3, 0xf3, 0xb, 0xa0, 0x5d, 0x22, 0xf5, 0xa, 0xb3, 0x21, 0x5b, 0xd7, 0x5c, 0xeb, 0xc6, 0x74, 0xfa, 0x6b, 0x3a, 0x35, 0xf3, 0xd6, 0x64, 0x6b, 0xde, 0xdd, 0x73, 0xf, 0xed, 0xe, 0x71, 0x0, 0x22, 0xdd, 0xc7, 0x27, 0x83, 0x1d, 0x6a, 0xb1, 0xf9, 0xc, 0x5e, 0xda, 0xaf, 0x2a, 0x1, 0xf5, 0x6e, 0xe7, 0xed, 0x7d, 0x89, 0x9d, 0x7a, 0x79, 0xe5, 0xe3, 0xd3, 0xf5, 0x85, 0x90, 0xdd, 0x9f, 0xc1, 0xb6, 0xf0, 0xea, 0xda, 0x7f, 0x3e, 0xeb, 0xaf, 0xef, 0xfe, 0x6, 0x1a, 0x96, 0x59, 0x89, 0x91, 0xf7, 0xf1, 0x7b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0x8, 0xd9, 0x10, 0xcb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x91, 0x53, 0x62, 0x5, 0x41, 0x14, 0x44, 0xab, 0x46, 0xb1, 0x6d, 0x67, 0x3, 0x59, 0x44, 0x16, 0x9e, 0xdf, 0xe8, 0x2f, 0xb6, 0xcd, 0xe7, 0x61, 0xe3, 0x3e, 0x4e, 0xb5, 0x2e, 0x4e, 0xdb, 0xa3, 0x11, 0x80, 0xc4, 0x51, 0xc6, 0x3f, 0x5a, 0xe5, 0xb1, 0x4f, 0x8, 0xd5, 0xff, 0x15, 0xd1, 0x26, 0xba, 0x7d, 0xbd, 0xec, 0xa3, 0x75, 0x94, 0x24, 0x11, 0xbb, 0xe1, 0x2f, 0x1f, 0xe0, 0x91, 0xde, 0x8, 0xf3, 0x1, 0xe, 0x3d, 0x42, 0x1, 0xe3, 0x49, 0xf, 0x1a, 0xc0, 0xb7, 0xb5, 0x47, 0x92, 0x52, 0xb7, 0x3b, 0x79, 0xa7, 0x80, 0x21, 0xc2, 0x2a, 0xa9, 0x15, 0x8b, 0x8e, 0x1c, 0x2e, 0x64, 0x71, 0x4, 0xd0, 0x5b, 0x34, 0x80, 0xa0, 0x34, 0x29, 0xab, 0xd5, 0x7a, 0xfb, 0x5e, 0xc2, 0x51, 0xc0, 0x3, 0x83, 0x6, 0x10, 0xa2, 0xa1, 0x62, 0x1f, 0xf0, 0xae, 0x0, 0x38, 0xd, 0xe0, 0x67, 0xfe, 0xe9, 0xb, 0x72, 0x86, 0xb7, 0x5, 0x46, 0xa, 0x48, 0xfc, 0xa6, 0x15, 0x1e, 0x96, 0xc5, 0x79, 0x99, 0xbe, 0x78, 0x59, 0x2c, 0x1, 0x5e, 0x92, 0x34, 0x6d, 0xb1, 0xf9, 0xda, 0x75, 0x66, 0x6d, 0xfa, 0xf3, 0x5, 0x7f, 0x58, 0x3, 0x8d, 0x15, 0xc8, 0x85, 0xf3, 0xd, 0x6b, 0x1f, 0xdf, 0x6e, 0x8c, 0x33, 0xd4, 0xc0, 0xce, 0xd6, 0xa8, 0x0, 0xd5, 0x20, 0xbc, 0xb5, 0xf6, 0xc2, 0x68, 0xb6, 0xf4, 0x8d, 0x6, 0x9c, 0xc3, 0x6d, 0x5a, 0x60, 0xf, 0x53, 0x7d, 0x72, 0x86, 0x6a, 0xf4, 0xf1, 0xed, 0x1, 0x74, 0x5a, 0x3f, 0xab, 0x94, 0xee, 0x3f, 0x7a, 0x64, 0x11, 0x8a, 0x6e, 0x0, 0x80, 0xdd, 0x4f, 0x5c, 0xe, 0xd7, 0x26, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_button_pressed_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x4d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0xff, 0xff, 0xff, 0x2, 0x4e, 0xff, 0xf1, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6e, 0x22, 0xf, 0x51, 0x17, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0x57, 0x53, 0xc2, 0x40, 0x10, 0xc0, 0x71, 0x6a, 0x50, 0x54, 0x5a, 0xec, 0xbd, 0x43, 0x14, 0xf5, 0x2e, 0x91, 0xa8, 0x5c, 0x12, 0x20, 0x18, 0xd, 0x22, 0x88, 0xd, 0x8d, 0xd, 0xb0, 0xd7, 0xef, 0xff, 0xea, 0x71, 0xd9, 0x63, 0x18, 0x7d, 0xd0, 0xdf, 0xf3, 0x7f, 0xe6, 0x76, 0xf7, 0x3c, 0x5e, 0x9f, 0x3f, 0x10, 0x14, 0x42, 0x94, 0xd0, 0xd3, 0x1b, 0xee, 0xeb, 0xf7, 0xfc, 0xe4, 0x1b, 0x88, 0x44, 0x63, 0xf1, 0x84, 0x28, 0x8a, 0x83, 0x43, 0xc3, 0x23, 0x61, 0xef, 0xaf, 0xc0, 0x1f, 0x19, 0x1d, 0x5b, 0x5c, 0x72, 0x2d, 0x27, 0x53, 0xd2, 0xa, 0x58, 0x95, 0xd2, 0xa9, 0xf1, 0x9, 0x1a, 0x4, 0xa2, 0x93, 0x6b, 0xeb, 0x60, 0x3, 0x61, 0x59, 0x1, 0x9b, 0x72, 0x46, 0x55, 0xa7, 0x68, 0x10, 0x8c, 0x6d, 0x6d, 0x73, 0x3b, 0x59, 0xa2, 0xa5, 0x81, 0xae, 0xc9, 0xc4, 0x90, 0x69, 0x20, 0xc4, 0x73, 0x79, 0x2e, 0x97, 0x45, 0x49, 0x9, 0x14, 0x74, 0x5, 0x99, 0xed, 0x20, 0x94, 0x28, 0xee, 0x72, 0x45, 0xb, 0xe9, 0x7b, 0xa0, 0xb0, 0x6f, 0x23, 0xc3, 0x6a, 0x7, 0x62, 0xe9, 0x80, 0x2b, 0x75, 0x7, 0x3a, 0xd, 0x10, 0xb, 0xca, 0x87, 0x5c, 0x39, 0x53, 0x51, 0xba, 0x66, 0xa8, 0x1e, 0x11, 0xf6, 0x44, 0xed, 0x98, 0xab, 0x61, 0x7c, 0x72, 0xa, 0xb4, 0x33, 0xa4, 0x9e, 0x63, 0x36, 0x64, 0xfd, 0x82, 0xab, 0x5f, 0x9a, 0x4e, 0x67, 0x4d, 0xa7, 0x62, 0x5e, 0x99, 0x6c, 0xcd, 0xeb, 0x9b, 0x5b, 0x70, 0xd7, 0x68, 0x12, 0x7, 0x20, 0xd2, 0xba, 0x7f, 0x30, 0xd8, 0xa1, 0xa6, 0x1f, 0x9f, 0x9e, 0x5d, 0x2f, 0x8d, 0x57, 0x95, 0x80, 0x6a, 0xab, 0xf9, 0xf6, 0x3e, 0xc3, 0x4e, 0x3d, 0x3b, 0xf7, 0xf1, 0xe9, 0xfa, 0x42, 0xc8, 0xee, 0xcc, 0x60, 0x5b, 0x78, 0x7e, 0xe1, 0x3f, 0x9f, 0xf5, 0xd7, 0x77, 0x7f, 0x3, 0x1c, 0x7f, 0x59, 0xc2, 0x5e, 0xdd, 0xbf, 0x43, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x4a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0x10, 0x9d, 0xe0, 0x3c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xcf, 0x3, 0x62, 0x4, 0x51, 0x10, 0x4, 0xd0, 0xaa, 0x31, 0x62, 0xdb, 0xb8, 0x49, 0x2e, 0x9e, 0x3b, 0xc4, 0xb6, 0x9d, 0xc5, 0x58, 0x1f, 0xc1, 0xd6, 0xe8, 0x77, 0xf7, 0x1b, 0x59, 0x6c, 0x2, 0x20, 0x37, 0xaa, 0xc5, 0x17, 0x7e, 0xc7, 0x62, 0x28, 0x45, 0x75, 0xfe, 0x6c, 0xe1, 0x4f, 0x68, 0x86, 0x41, 0x69, 0x44, 0x51, 0x4b, 0xb1, 0xce, 0xcc, 0xe4, 0x83, 0xd7, 0xb0, 0x48, 0x6b, 0x98, 0xe8, 0x9, 0x38, 0x70, 0x8b, 0xa, 0xcc, 0x12, 0x1a, 0xf0, 0x4d, 0xac, 0x87, 0xf3, 0x96, 0x6f, 0x8e, 0x5f, 0x56, 0xc0, 0x53, 0x20, 0x8f, 0xbf, 0xdb, 0x86, 0x58, 0x5b, 0x9, 0xbf, 0x47, 0x80, 0xa, 0x58, 0x1a, 0x38, 0xad, 0x9, 0x5f, 0xac, 0xe3, 0x20, 0xbc, 0x4b, 0x46, 0x4b, 0x0, 0x3a, 0x1a, 0x24, 0xd0, 0x69, 0x85, 0xc0, 0x63, 0x5, 0x60, 0x68, 0xf0, 0x36, 0x7f, 0xf3, 0xaa, 0xbe, 0xe1, 0x61, 0x81, 0x69, 0x5, 0x72, 0x5b, 0x83, 0xe4, 0x6a, 0x59, 0x16, 0xf7, 0x53, 0x47, 0x77, 0x8b, 0xad, 0x12, 0xe4, 0xb9, 0xa3, 0xc1, 0xe6, 0x83, 0x7b, 0x20, 0xd6, 0xb4, 0xe7, 0xbf, 0xed, 0xe1, 0x1a, 0xd8, 0xfa, 0xdf, 0xb9, 0x70, 0xb8, 0x21, 0xd6, 0xbb, 0x17, 0x1b, 0xe3, 0x4c, 0x6a, 0xb0, 0xbd, 0x25, 0x5, 0x3b, 0x5e, 0x7c, 0x21, 0xc0, 0xc2, 0x68, 0xee, 0xf1, 0xbc, 0x6, 0x46, 0xb1, 0xbd, 0x5e, 0x30, 0x5, 0x27, 0x19, 0x24, 0xb8, 0x61, 0x6e, 0xf8, 0xf5, 0xf7, 0xcd, 0x47, 0x16, 0xa0, 0x18, 0x13, 0x6a, 0x64, 0x7d, 0xff, 0x8f, 0x1e, 0x59, 0x84, 0xa2, 0x1b, 0x0, 0xe5, 0xe0, 0x4e, 0x46, 0x1d, 0x98, 0x92, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char panel_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char popup_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xa5, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x35, 0x32, 0x3b, 0xf, 0xeb, 0x7f, 0x60, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x36, 0x47, 0xbf, 0x88, 0xd1, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xaf, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0xc9, 0x12, 0x82, 0x30, 0x10, 0x4, 0xd0, 0x1, 0x12, 0xb6, 0x0, 0x21, 0x2c, 0xb2, 0xaa, 0xa0, 0xa8, 0x80, 0x88, 0x8, 0xf8, 0xff, 0xbf, 0x66, 0x98, 0x93, 0xa5, 0xef, 0xd8, 0x55, 0xd3, 0xd5, 0x3, 0xa0, 0xa8, 0x1a, 0xa1, 0xba, 0x44, 0x89, 0xa6, 0x2a, 0x0, 0x8a, 0x41, 0x4d, 0xcb, 0x66, 0x8e, 0xc3, 0x6c, 0xcb, 0xa4, 0x86, 0x2, 0x2a, 0x75, 0x3d, 0xee, 0x8b, 0x20, 0x10, 0x3e, 0xf7, 0x5c, 0xaa, 0x82, 0x66, 0x7a, 0x61, 0x14, 0xef, 0xa4, 0x38, 0xa, 0x3d, 0x53, 0x3, 0x62, 0xf1, 0xa4, 0xed, 0x50, 0x9b, 0x70, 0x8b, 0x0, 0xb5, 0xd3, 0xac, 0xeb, 0x51, 0x97, 0xa5, 0x36, 0x5, 0x9d, 0x89, 0xbc, 0xbf, 0xa3, 0x3e, 0x17, 0x4c, 0x7, 0xdd, 0x9, 0x8a, 0xe1, 0x81, 0x86, 0x22, 0x70, 0x30, 0x28, 0xc7, 0x27, 0x1a, 0x4b, 0xc, 0x98, 0xd8, 0x4f, 0x2f, 0x34, 0xed, 0xb7, 0x13, 0x59, 0x7a, 0x98, 0x17, 0x34, 0x1f, 0xb7, 0x52, 0x52, 0xf1, 0x7a, 0x5d, 0xde, 0xd2, 0xb2, 0x9e, 0x78, 0x45, 0xb6, 0x61, 0xe7, 0xba, 0xb9, 0x48, 0xcd, 0xf5, 0xb6, 0xd, 0xc3, 0xe9, 0xe9, 0xd7, 0xf4, 0xbf, 0xe7, 0x7e, 0xdf, 0xff, 0x0, 0xda, 0x19, 0x15, 0x34, 0xd5, 0xa4, 0x90, 0x50, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xa2, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x36, 0xc6, 0xc8, 0x93, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0x8f, 0x35, 0x82, 0xc3, 0x0, 0xc, 0x4, 0x77, 0x24, 0x85, 0xba, 0xe3, 0xff, 0xff, 0xee, 0xca, 0x74, 0x41, 0xdb, 0x32, 0xf3, 0x94, 0x82, 0x85, 0x10, 0x1d, 0x92, 0xb2, 0x3, 0x8e, 0x95, 0x77, 0x93, 0x6c, 0x28, 0xed, 0x15, 0x54, 0x67, 0xa6, 0x41, 0x3e, 0x8, 0x9c, 0xc3, 0xf4, 0xf2, 0xf6, 0x2a, 0x80, 0xf8, 0x44, 0x2d, 0x79, 0x2d, 0x20, 0xe0, 0x2, 0xa8, 0xc3, 0x2e, 0x6f, 0xc, 0x9e, 0x4c, 0x3c, 0x21, 0x4, 0xd8, 0xf0, 0x2, 0x28, 0x24, 0xcd, 0x3, 0xa9, 0x19, 0x64, 0xce, 0x83, 0x4c, 0x45, 0xe6, 0x69, 0x1a, 0xd8, 0xe9, 0x99, 0x96, 0x7f, 0x77, 0x37, 0x59, 0x83, 0xcc, 0xef, 0x7f, 0x89, 0x1f, 0x8e, 0xbf, 0x95, 0xd3, 0x1d, 0xf0, 0xff, 0x7a, 0x63, 0x7e, 0x86, 0xcb, 0x73, 0x8c, 0x5e, 0xee, 0xca, 0xb1, 0xad, 0x5f, 0x3, 0xaf, 0xdb, 0x49, 0x94, 0x4b, 0x90, 0x40, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char popup_bg_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x7b, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x67, 0x7a, 0x85, 0x66, 0x7a, 0x86, 0x68, 0x7b, 0x86, 0x57, 0x51, 0x51, 0x4c, 0x42, 0x40, 0x4d, 0x43, 0x41, 0x56, 0x4c, 0x4b, 0x4d, 0x44, 0x41, 0x4e, 0x44, 0x42, 0x4f, 0x45, 0x43, 0x67, 0x7b, 0x87, 0x4f, 0x44, 0x43, 0x50, 0x45, 0x44, 0x52, 0x46, 0x44, 0x51, 0x46, 0x45, 0x4b, 0x40, 0x3f, 0x51, 0x47, 0x45, 0x52, 0x48, 0x46, 0x53, 0x48, 0x47, 0x4b, 0x41, 0x3f, 0x54, 0x49, 0x46, 0x55, 0x4a, 0x47, 0x55, 0x49, 0x47, 0x68, 0x7c, 0x88, 0x4a, 0x40, 0x3e, 0x55, 0x4b, 0x49, 0x56, 0x4d, 0x4b, 0x53, 0x49, 0x47, 0x50, 0x46, 0x44, 0x4a, 0x41, 0x3e, 0x48, 0x3e, 0x3c, 0x4b, 0x42, 0x3f, 0x49, 0x3f, 0x3d, 0x46, 0x3d, 0x3c, 0x47, 0x3d, 0x3b, 0x47, 0x3e, 0x3b, 0x49, 0x40, 0x3d, 0x45, 0x3c, 0x3b, 0x46, 0x3c, 0x3a, 0xff, 0xff, 0xff, 0x2e, 0x48, 0xbd, 0x3e, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x28, 0xbd, 0xb0, 0xb5, 0xb2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb3, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x2d, 0x8f, 0xdb, 0x16, 0x82, 0x20, 0x10, 0x45, 0x11, 0x19, 0x12, 0x91, 0x54, 0x44, 0x93, 0xb2, 0x48, 0xa1, 0xfc, 0xff, 0x3f, 0xec, 0xa0, 0xed, 0xb7, 0xd9, 0x73, 0xd6, 0x5c, 0x18, 0x3, 0x5, 0x2f, 0x1, 0x2f, 0xd8, 0x49, 0xc1, 0x5, 0x49, 0x40, 0xe2, 0x54, 0xc5, 0x85, 0x2a, 0xa9, 0x80, 0xac, 0x48, 0x64, 0xc3, 0x89, 0x64, 0x7d, 0x20, 0x89, 0x34, 0x2, 0x82, 0x48, 0x35, 0xe6, 0x7a, 0x6d, 0x1b, 0x45, 0x39, 0xc2, 0x3b, 0x92, 0x4d, 0x6f, 0x87, 0xc1, 0xf6, 0x30, 0x4e, 0x33, 0xed, 0xb2, 0x18, 0xa7, 0xdb, 0x64, 0x8d, 0x24, 0x37, 0x33, 0xed, 0x9d, 0xac, 0xfb, 0xf1, 0xfe, 0x18, 0x97, 0xa7, 0x3a, 0xc4, 0xcb, 0x51, 0x16, 0xf7, 0xc9, 0x42, 0x78, 0x88, 0xf0, 0x76, 0xca, 0xb4, 0xcb, 0x62, 0xd, 0x2, 0x2b, 0xc4, 0x16, 0x7c, 0x5e, 0x63, 0x9e, 0x35, 0x75, 0x6b, 0xd4, 0x58, 0x9b, 0x3e, 0x98, 0x8b, 0xbb, 0xd0, 0x8f, 0xa2, 0x64, 0x88, 0xc4, 0xb0, 0x7a, 0xe7, 0x3a, 0x1f, 0x12, 0x2, 0xf9, 0xb2, 0x6f, 0x8c, 0x31, 0x84, 0x18, 0xd3, 0x26, 0xf8, 0xf1, 0x8c, 0x16, 0xfb, 0x9e, 0xd2, 0xbe, 0xb, 0x5d, 0xfe, 0xff, 0xe5, 0x7a, 0x6, 0x67, 0xf9, 0x3, 0x92, 0x36, 0xd, 0x2d, 0xc1, 0xf2, 0x6d, 0x3c, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x78, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x67, 0x7a, 0x85, 0x66, 0x7a, 0x86, 0x68, 0x7b, 0x86, 0x57, 0x51, 0x51, 0x4c, 0x42, 0x40, 0x4d, 0x43, 0x41, 0x56, 0x4c, 0x4b, 0x4d, 0x44, 0x41, 0x4e, 0x44, 0x42, 0x4f, 0x45, 0x43, 0x67, 0x7b, 0x87, 0x4f, 0x44, 0x43, 0x50, 0x45, 0x44, 0x52, 0x46, 0x44, 0x51, 0x46, 0x45, 0x4b, 0x40, 0x3f, 0x51, 0x47, 0x45, 0x52, 0x48, 0x46, 0x53, 0x48, 0x47, 0x4b, 0x41, 0x3f, 0x54, 0x49, 0x46, 0x55, 0x4a, 0x47, 0x55, 0x49, 0x47, 0x68, 0x7c, 0x88, 0x4a, 0x40, 0x3e, 0x55, 0x4b, 0x49, 0x56, 0x4d, 0x4b, 0x53, 0x49, 0x47, 0x50, 0x46, 0x44, 0x4a, 0x41, 0x3e, 0x48, 0x3e, 0x3c, 0x4b, 0x42, 0x3f, 0x49, 0x3f, 0x3d, 0x46, 0x3d, 0x3c, 0x47, 0x3d, 0x3b, 0x47, 0x3e, 0x3b, 0x49, 0x40, 0x3d, 0x45, 0x3c, 0x3b, 0x46, 0x3c, 0x3a, 0xdd, 0x63, 0x56, 0x8d, 0x0, 0x0, 0x0, 0xad, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2d, 0x88, 0x35, 0x42, 0x4, 0x0, 0xc, 0x4, 0x77, 0x93, 0x9c, 0xbb, 0xf4, 0xc8, 0xff, 0xdf, 0x84, 0xb5, 0xb8, 0x5b, 0x84, 0x0, 0x37, 0xc5, 0xca, 0x10, 0xd, 0xc9, 0xce, 0xaa, 0xea, 0x24, 0x40, 0xca, 0x41, 0x64, 0x2b, 0x5, 0x87, 0x34, 0xa8, 0x88, 0x54, 0xef, 0x82, 0x80, 0x89, 0x34, 0x36, 0x96, 0xe0, 0x14, 0xa4, 0x12, 0xa6, 0x24, 0x18, 0xe1, 0xa8, 0x50, 0x59, 0x7c, 0x73, 0x30, 0x50, 0x55, 0x4a, 0x31, 0xd7, 0xb4, 0x89, 0xa1, 0x51, 0xb2, 0x9c, 0x1, 0x2c, 0x4, 0x83, 0x15, 0x12, 0x30, 0xab, 0xe9, 0x5a, 0x1, 0xb4, 0x40, 0xa1, 0x29, 0xbe, 0x75, 0xe, 0x5a, 0x70, 0xbe, 0x2a, 0xff, 0x12, 0xf1, 0xef, 0x1b, 0x5f, 0x8d, 0x5b, 0x68, 0xd, 0xdc, 0xe3, 0xf1, 0x71, 0x16, 0x3e, 0x5b, 0xc8, 0x33, 0xa9, 0xc7, 0xbc, 0x7f, 0xa4, 0x22, 0x6a, 0xb5, 0x90, 0xcb, 0xb2, 0x1a, 0x25, 0x67, 0x8b, 0x8f, 0x6f, 0xf8, 0x64, 0xa8, 0x35, 0x7a, 0x25, 0xa8, 0xa7, 0x1, 0x38, 0xc, 0xcc, 0xab, 0x4c, 0x5, 0xea, 0xe3, 0x76, 0x2f, 0x54, 0x93, 0xf3, 0xf, 0x4f, 0x10, 0x8d, 0x4c, 0x16, 0x9d, 0xcf, 0x1f, 0xd1, 0xf9, 0x3, 0x34, 0xc8, 0x4a, 0xb4, 0x1d, 0xb, 0xcd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char popup_checked_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xa3, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x85, 0xcd, 0xa1, 0xa, 0xc2, 0x50, 0x0, 0x85, 0xe1, 0xff, 0xdc, 0x5d, 0xd8, 0x14, 0x4, 0xab, 0x69, 0x37, 0xac, 0x98, 0xd5, 0x27, 0xb0, 0x89, 0x16, 0x8b, 0xd5, 0xf7, 0xd0, 0xec, 0x73, 0xf8, 0x4, 0x16, 0x61, 0x4d, 0x10, 0xc, 0x16, 0xa3, 0x61, 0x71, 0xab, 0x16, 0xeb, 0x84, 0x3b, 0xae, 0x45, 0x8b, 0xa, 0x9e, 0x78, 0xce, 0x7, 0x7, 0xfe, 0x44, 0xbf, 0xca, 0xa2, 0x28, 0x3a, 0x71, 0x1c, 0x1f, 0x24, 0x3d, 0xcc, 0xe7, 0x18, 0x42, 0x50, 0x92, 0x24, 0x5b, 0x49, 0x23, 0xa0, 0xfd, 0x5, 0xaa, 0xaa, 0x5a, 0x1, 0x73, 0xe0, 0x1e, 0x45, 0xd1, 0x42, 0x65, 0x59, 0x9e, 0x80, 0x96, 0xf7, 0x7e, 0x62, 0xad, 0x1d, 0x2, 0xfb, 0x97, 0x9d, 0x39, 0xe7, 0x72, 0x1b, 0x42, 0x88, 0x25, 0xd, 0xac, 0xb5, 0x47, 0xa0, 0x7, 0x18, 0x60, 0xed, 0x9c, 0xcb, 0x1, 0x4c, 0xd3, 0x34, 0x53, 0xe0, 0xa, 0xf4, 0x81, 0x2e, 0xb0, 0x4b, 0xd3, 0x74, 0xf3, 0xbe, 0x34, 0x59, 0x96, 0xdd, 0xbc, 0xf7, 0x63, 0xe0, 0x2, 0x9c, 0xeb, 0xba, 0x5e, 0x4a, 0xa, 0x6f, 0xf0, 0x4, 0x57, 0x3d, 0x2c, 0x27, 0x2b, 0xe9, 0x62, 0x6b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x56, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x3, 0x6e, 0xf0, 0xde, 0x3f, 0xf5, 0xe0, 0x30, 0x9c, 0xfb, 0x9f, 0xf1, 0xc1, 0xda, 0x7, 0xff, 0x1f, 0x9c, 0x85, 0xb, 0x3c, 0xa8, 0x1, 0x72, 0xdf, 0x3d, 0x56, 0x61, 0x78, 0x70, 0xf8, 0xc1, 0x99, 0x3b, 0x62, 0xf, 0xbc, 0x1e, 0xfc, 0x5, 0x42, 0x2f, 0xa0, 0xcc, 0xfd, 0x53, 0x40, 0x99, 0x6b, 0xf, 0xde, 0x3, 0xc9, 0x6a, 0xb0, 0x52, 0xa0, 0xec, 0xe5, 0x7, 0xff, 0x81, 0x70, 0xed, 0x7f, 0x46, 0x20, 0x17, 0x2a, 0x74, 0xfa, 0xc1, 0xb1, 0x1b, 0xbc, 0x10, 0x1e, 0x0, 0xfd, 0x1f, 0x33, 0x9, 0xf7, 0x50, 0x16, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char popup_hover_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x20, 0x2e, 0x31, 0x83, 0xae, 0xb7, 0xb3, 0xd8, 0xe1, 0xaf, 0xd5, 0xde, 0xac, 0xd2, 0xdb, 0xa9, 0xcf, 0xd8, 0xa5, 0xcc, 0xd5, 0xa2, 0xc9, 0xd2, 0x9e, 0xc6, 0xcf, 0x9b, 0xc3, 0xcc, 0x97, 0xc0, 0xc9, 0x94, 0xbd, 0xc6, 0x91, 0xba, 0xc3, 0x8d, 0xb7, 0xc0, 0xff, 0xff, 0xff, 0x73, 0xd4, 0x4e, 0xcb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x14, 0x4, 0x3, 0x1, 0x6, 0x21, 0x25, 0x30, 0x50, 0x64, 0x10, 0x32, 0x6, 0x3, 0x20, 0xc3, 0x5, 0xc, 0x80, 0x8c, 0x50, 0x30, 0x0, 0x32, 0xd2, 0xc0, 0x0, 0xc8, 0x28, 0x7, 0x3, 0x20, 0xa3, 0x3, 0xc, 0x80, 0x8c, 0x99, 0x60, 0x0, 0x64, 0xac, 0x2, 0x3, 0x20, 0x63, 0x37, 0x18, 0x0, 0x19, 0x67, 0xc0, 0x0, 0xc8, 0xb8, 0xb, 0x6, 0x40, 0xc6, 0x3b, 0x30, 0x50, 0x44, 0x58, 0xa, 0x73, 0x6, 0x0, 0xe9, 0xb4, 0x2d, 0xf5, 0x51, 0xd4, 0xb8, 0xa1, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x20, 0x2e, 0x31, 0x83, 0xae, 0xb7, 0xb3, 0xd8, 0xe1, 0xaf, 0xd5, 0xde, 0xac, 0xd2, 0xdb, 0xa9, 0xcf, 0xd8, 0xa5, 0xcc, 0xd5, 0xa2, 0xc9, 0xd2, 0x9e, 0xc6, 0xcf, 0x9b, 0xc3, 0xcc, 0x97, 0xc0, 0xc9, 0x94, 0xbd, 0xc6, 0x91, 0xba, 0xc3, 0x8d, 0xb7, 0xc0, 0x9c, 0x2c, 0x91, 0xa9, 0x0, 0x0, 0x0, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x62, 0x14, 0x4, 0x3, 0x1, 0x26, 0x41, 0x28, 0x60, 0x62, 0x80, 0xd0, 0xc, 0x74, 0x61, 0x98, 0x80, 0x1, 0x3, 0xd3, 0x7b, 0x28, 0x0, 0x0, 0x1a, 0x86, 0xe, 0x98, 0x2c, 0x61, 0xda, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char popup_unchecked_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x18, 0x32, 0xe0, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x18, 0x32, 0xe0, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char popup_window_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x46, 0x8, 0x3, 0x0, 0x0, 0x0, 0x8d, 0x2b, 0xf6, 0x48, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x6e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xe8, 0xe5, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x22, 0x0, 0x0, 0x0, 0x1a, 0x19, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x21, 0x17, 0x16, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1b, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1e, 0x1c, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x0, 0x0, 0x0, 0x20, 0x20, 0x25, 0x20, 0x1d, 0x25, 0x20, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x20, 0x1d, 0x1a, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30, 0x38, 0xe8, 0xe5, 0xf1, 0xe5, 0xe2, 0xeb, 0xe3, 0xe1, 0xe8, 0xe1, 0xdf, 0xe7, 0xe0, 0xde, 0xe6, 0xdf, 0xdd, 0xe5, 0xde, 0xdc, 0xe4, 0xdd, 0xdb, 0xe3, 0xdc, 0xda, 0xe2, 0xda, 0xd8, 0xe0, 0xd9, 0xd7, 0xdf, 0xd7, 0xd6, 0xdf, 0xd6, 0xd4, 0xdd, 0xd5, 0xd3, 0xdc, 0xd4, 0xd1, 0xdb, 0xd3, 0xd0, 0xda, 0xd1, 0xce, 0xd8, 0xd0, 0xcd, 0xd7, 0xcf, 0xcd, 0xd7, 0xe2, 0xdf, 0xeb, 0x48, 0x46, 0x51, 0x42, 0x40, 0x4b, 0x40, 0x3e, 0x48, 0x40, 0x3d, 0x48, 0x48, 0x45, 0x50, 0x42, 0x3f, 0x4a, 0x3f, 0x3d, 0x48, 0x47, 0x44, 0x50, 0x41, 0x3f, 0x4a, 0x3f, 0x3d, 0x47, 0x41, 0x3e, 0x49, 0x3f, 0x3c, 0x47, 0x46, 0x43, 0x4f, 0x3e, 0x3c, 0x46, 0x40, 0x3e, 0x49, 0x3d, 0x3b, 0x46, 0x45, 0x43, 0x4e, 0x3d, 0x3b, 0x45, 0x44, 0x42, 0x4d, 0x3d, 0x3a, 0x45, 0x3e, 0x3c, 0x47, 0x3c, 0x3a, 0x44, 0x43, 0x42, 0x4c, 0x43, 0x40, 0x4c, 0x3e, 0x3b, 0x46, 0x3b, 0x39, 0x43, 0x43, 0x3f, 0x4c, 0x43, 0x3f, 0x4b, 0x3a, 0x38, 0x42, 0x42, 0x3e, 0x4b, 0x42, 0x3e, 0x49, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3f, 0x3e, 0x48, 0x39, 0x37, 0x40, 0x38, 0x36, 0x40, 0x3e, 0x3d, 0x48, 0x38, 0x36, 0x3f, 0x3e, 0x3d, 0x47, 0x3a, 0x38, 0x41, 0x38, 0x35, 0x3f, 0x37, 0x35, 0x3e, 0x39, 0x36, 0x40, 0x37, 0x34, 0x3e, 0x3d, 0x3a, 0x46, 0x36, 0x34, 0x3d, 0x3d, 0x3a, 0x44, 0x37, 0x35, 0x3f, 0x35, 0x33, 0x3c, 0x46, 0x44, 0x4f, 0xff, 0xff, 0xff, 0x7e, 0xde, 0x1d, 0x81, 0x0, 0x0, 0x0, 0x33, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xa2, 0x3, 0x9, 0x17, 0xc, 0x20, 0xf, 0x2a, 0x5e, 0x12, 0x30, 0x68, 0x46, 0x20, 0x4e, 0xa2, 0x7d, 0x3a, 0x4f, 0xa4, 0x7d, 0x3f, 0x25, 0x60, 0xc0, 0xb8, 0x57, 0x1d, 0xba, 0x59, 0xbd, 0x5b, 0x22, 0xbf, 0x5e, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xa1, 0x9f, 0x9e, 0x52, 0x92, 0x15, 0x44, 0x7e, 0xd8, 0x5, 0xc7, 0xf4, 0xac, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x79, 0xa1, 0xdc, 0xd4, 0xd0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0xe8, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0xd6, 0xd9, 0x53, 0xd3, 0x60, 0x14, 0xc6, 0xe1, 0x92, 0x5a, 0xa3, 0x44, 0xa3, 0xd6, 0x85, 0xa0, 0xb1, 0x5a, 0xcb, 0xda, 0xbd, 0x7c, 0xb8, 0xef, 0x2b, 0x69, 0x21, 0xd0, 0xda, 0x22, 0x25, 0xd, 0x69, 0x20, 0x60, 0x69, 0x11, 0x2a, 0x22, 0xcb, 0x9f, 0xef, 0x78, 0x97, 0x7e, 0xe7, 0x3d, 0x33, 0x1d, 0xbd, 0x70, 0xfc, 0x5d, 0x3f, 0x77, 0xe7, 0xe2, 0x3d, 0x91, 0xc8, 0x7f, 0xd8, 0x88, 0x60, 0x1a, 0x21, 0x54, 0xcc, 0x3f, 0x84, 0xcd, 0xb, 0x4a, 0x1f, 0x31, 0xfd, 0x1d, 0x7d, 0xcc, 0x4, 0xe8, 0x13, 0x26, 0x40, 0x9f, 0x32, 0x1, 0xfa, 0x8c, 0x9, 0xd0, 0xe7, 0x4c, 0x80, 0xbe, 0x60, 0x2, 0xf4, 0x25, 0x13, 0xa0, 0xaf, 0x98, 0x0, 0x7d, 0xcd, 0x44, 0xa8, 0x22, 0xde, 0x30, 0x49, 0x54, 0x89, 0x9e, 0x13, 0x6f, 0x99, 0x64, 0x1a, 0x3b, 0x2f, 0xde, 0x31, 0x49, 0x54, 0xbd, 0x70, 0x51, 0xbc, 0x67, 0x92, 0xe8, 0xa8, 0x76, 0x49, 0x7c, 0x60, 0x12, 0x97, 0xf5, 0x68, 0x88, 0xea, 0x57, 0xae, 0x8a, 0x8f, 0x4c, 0xe2, 0x5a, 0x7c, 0x34, 0x4c, 0xaf, 0xdf, 0x10, 0x9f, 0x98, 0xc4, 0xcd, 0x5b, 0x21, 0xaa, 0x8c, 0x19, 0xe3, 0xb, 0x56, 0x19, 0x66, 0x2d, 0xdc, 0xbe, 0x63, 0x2a, 0x43, 0xd2, 0xbb, 0x9, 0x7d, 0x58, 0x7a, 0xef, 0x7e, 0x72, 0x58, 0xfa, 0x20, 0x35, 0x36, 0x2c, 0x1d, 0x37, 0x8, 0xad, 0xc0, 0x0, 0x5d, 0x5c, 0xb2, 0x61, 0x4b, 0x8b, 0x32, 0x9d, 0x58, 0x5e, 0xa9, 0xc2, 0x56, 0x96, 0x27, 0x8, 0xad, 0x7d, 0x86, 0xd5, 0x28, 0xad, 0xd7, 0x1a, 0xb0, 0x5a, 0x9d, 0xd2, 0x55, 0x4c, 0x57, 0x1, 0xad, 0x7c, 0x81, 0x55, 0x8, 0x9d, 0x5c, 0xb3, 0x9b, 0x30, 0x7b, 0x6d, 0x52, 0xa2, 0x53, 0xeb, 0x55, 0x7, 0x56, 0x5d, 0x9f, 0x22, 0xb4, 0xe5, 0xc2, 0x5a, 0x94, 0x6e, 0x34, 0x30, 0x6d, 0x6c, 0x10, 0xea, 0xb5, 0x7d, 0x58, 0xdb, 0x93, 0xe9, 0xf4, 0x66, 0x13, 0xd3, 0xe6, 0xe6, 0xb4, 0x4c, 0xb7, 0x9c, 0x0, 0xe6, 0x6c, 0x11, 0xba, 0xed, 0x62, 0xea, 0x6e, 0x13, 0xba, 0xe3, 0x7e, 0x85, 0xb9, 0x3b, 0x84, 0x96, 0xfd, 0xe, 0xcc, 0x2f, 0x13, 0xba, 0xeb, 0x77, 0x61, 0xfe, 0x2e, 0xa1, 0x76, 0xd0, 0x83, 0x5, 0x36, 0xa1, 0x7b, 0xc1, 0x37, 0x58, 0xb0, 0x27, 0xd3, 0x99, 0xfd, 0x83, 0x3e, 0xec, 0x60, 0x7f, 0x46, 0xa2, 0xb3, 0xad, 0xce, 0x77, 0x58, 0xa7, 0x35, 0x2b, 0xd3, 0xf6, 0x21, 0xa6, 0x87, 0x6d, 0x40, 0x7f, 0xc0, 0x0, 0x3d, 0xea, 0xfd, 0x84, 0xf5, 0x8e, 0x8, 0x75, 0xfa, 0x98, 0xf6, 0x1d, 0x42, 0x8f, 0x39, 0x7a, 0x4c, 0xe9, 0xc9, 0x29, 0xec, 0x64, 0x90, 0x46, 0x92, 0xa9, 0xb4, 0x75, 0xca, 0x64, 0xa5, 0x53, 0xc9, 0xc8, 0x1f, 0xd2, 0xc, 0x4f, 0x33, 0x3, 0x54, 0x4f, 0x64, 0x79, 0x9a, 0x4d, 0xe8, 0x21, 0x6a, 0xe6, 0xf2, 0x1e, 0x47, 0xbd, 0x7c, 0xce, 0xc, 0xd1, 0x42, 0xb1, 0x54, 0xef, 0x62, 0xd9, 0x3d, 0x2b, 0x15, 0xb, 0x21, 0xaa, 0x6a, 0xc6, 0xdc, 0x99, 0x67, 0x81, 0xbc, 0xfa, 0x9c, 0xa1, 0xa9, 0x21, 0x1a, 0x35, 0xe3, 0x46, 0x29, 0x9f, 0xcd, 0xa4, 0xa5, 0x32, 0xd9, 0x7c, 0xc9, 0x88, 0x9b, 0xe1, 0xe1, 0x54, 0x62, 0xa6, 0x56, 0xcc, 0x25, 0x52, 0xa4, 0x44, 0xae, 0xa8, 0x99, 0xb1, 0xd0, 0x5, 0x7e, 0x3f, 0x4, 0x6a, 0xc1, 0xd4, 0x93, 0x24, 0xdd, 0x2c, 0xa8, 0xd1, 0x1, 0xf9, 0xf, 0xfb, 0x5, 0x66, 0x6f, 0x2a, 0x9a, 0xa8, 0x51, 0x81, 0xce, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x46, 0x8, 0x3, 0x0, 0x0, 0x0, 0x8d, 0x2b, 0xf6, 0x48, 0x0, 0x0, 0x1, 0x6b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xe8, 0xe5, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x22, 0x0, 0x0, 0x0, 0x1a, 0x19, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x21, 0x17, 0x16, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1b, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1e, 0x1c, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x0, 0x0, 0x0, 0x20, 0x20, 0x25, 0x20, 0x1d, 0x25, 0x20, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x20, 0x1d, 0x1a, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30, 0x38, 0xe8, 0xe5, 0xf1, 0xe5, 0xe2, 0xeb, 0xe3, 0xe1, 0xe8, 0xe1, 0xdf, 0xe7, 0xe0, 0xde, 0xe6, 0xdf, 0xdd, 0xe5, 0xde, 0xdc, 0xe4, 0xdd, 0xdb, 0xe3, 0xdc, 0xda, 0xe2, 0xda, 0xd8, 0xe0, 0xd9, 0xd7, 0xdf, 0xd7, 0xd6, 0xdf, 0xd6, 0xd4, 0xdd, 0xd5, 0xd3, 0xdc, 0xd4, 0xd1, 0xdb, 0xd3, 0xd0, 0xda, 0xd1, 0xce, 0xd8, 0xd0, 0xcd, 0xd7, 0xcf, 0xcd, 0xd7, 0xe2, 0xdf, 0xeb, 0x48, 0x46, 0x51, 0x42, 0x40, 0x4b, 0x40, 0x3e, 0x48, 0x40, 0x3d, 0x48, 0x48, 0x45, 0x50, 0x42, 0x3f, 0x4a, 0x3f, 0x3d, 0x48, 0x47, 0x44, 0x50, 0x41, 0x3f, 0x4a, 0x3f, 0x3d, 0x47, 0x41, 0x3e, 0x49, 0x3f, 0x3c, 0x47, 0x46, 0x43, 0x4f, 0x3e, 0x3c, 0x46, 0x40, 0x3e, 0x49, 0x3d, 0x3b, 0x46, 0x45, 0x43, 0x4e, 0x3d, 0x3b, 0x45, 0x44, 0x42, 0x4d, 0x3d, 0x3a, 0x45, 0x3e, 0x3c, 0x47, 0x3c, 0x3a, 0x44, 0x43, 0x42, 0x4c, 0x43, 0x40, 0x4c, 0x3e, 0x3b, 0x46, 0x3b, 0x39, 0x43, 0x43, 0x3f, 0x4c, 0x43, 0x3f, 0x4b, 0x3a, 0x38, 0x42, 0x42, 0x3e, 0x4b, 0x42, 0x3e, 0x49, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3f, 0x3e, 0x48, 0x39, 0x37, 0x40, 0x38, 0x36, 0x40, 0x3e, 0x3d, 0x48, 0x38, 0x36, 0x3f, 0x3e, 0x3d, 0x47, 0x3a, 0x38, 0x41, 0x38, 0x35, 0x3f, 0x37, 0x35, 0x3e, 0x39, 0x36, 0x40, 0x37, 0x34, 0x3e, 0x3d, 0x3a, 0x46, 0x36, 0x34, 0x3d, 0x3d, 0x3a, 0x44, 0x37, 0x35, 0x3f, 0x35, 0x33, 0x3c, 0x46, 0x44, 0x4f, 0xac, 0xa5, 0x1, 0x25, 0x0, 0x0, 0x0, 0x33, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xa2, 0x3, 0x9, 0x17, 0xc, 0x20, 0xf, 0x2a, 0x5e, 0x12, 0x30, 0x68, 0x46, 0x20, 0x4e, 0xa2, 0x7d, 0x3a, 0x4f, 0xa4, 0x7d, 0x3f, 0x25, 0x60, 0xc0, 0xb8, 0x57, 0x1d, 0xba, 0x59, 0xbd, 0x5b, 0x22, 0xbf, 0x5e, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xa1, 0x9f, 0x9e, 0x52, 0x92, 0x15, 0x44, 0x7e, 0xd8, 0x5, 0xc7, 0xf4, 0xac, 0x0, 0x0, 0x1, 0x98, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xd6, 0x55, 0x9e, 0x14, 0x31, 0x10, 0x80, 0xf1, 0xb2, 0x20, 0x1d, 0xdc, 0x9d, 0x3b, 0x2c, 0xa7, 0x87, 0x4b, 0xe0, 0xee, 0xd0, 0x82, 0xcb, 0xea, 0xb4, 0x86, 0x79, 0x23, 0x93, 0xaa, 0xcc, 0xf, 0xd7, 0xfd, 0x9e, 0xff, 0xed, 0x1d, 0x21, 0xf8, 0xe2, 0xfe, 0x1c, 0x8a, 0x17, 0x32, 0xa1, 0xa2, 0x2b, 0x48, 0x66, 0xb8, 0xa2, 0x28, 0x10, 0x9a, 0xd1, 0xf7, 0x3d, 0x16, 0x66, 0xfa, 0x45, 0x74, 0x9b, 0xd2, 0x97, 0x52, 0xe2, 0x2f, 0xa6, 0x40, 0x5f, 0x4c, 0x1d, 0xf3, 0x97, 0x52, 0x5e, 0x46, 0xf7, 0xee, 0xe3, 0x88, 0x8a, 0x48, 0x9e, 0x8a, 0xec, 0x8c, 0x28, 0x2c, 0xa7, 0xf0, 0x99, 0xd2, 0x6e, 0xe7, 0x8e, 0x10, 0x9b, 0xd1, 0x11, 0xe7, 0xe, 0xd1, 0x17, 0x8e, 0x2, 0xe6, 0x55, 0xf8, 0x42, 0x4a, 0x74, 0x18, 0xbe, 0xf8, 0xac, 0x9b, 0x5f, 0x4a, 0xb7, 0x36, 0x20, 0xa5, 0xf9, 0x2f, 0x90, 0x50, 0x11, 0x36, 0x13, 0x49, 0xa9, 0xe7, 0x6c, 0x5e, 0xcf, 0x2e, 0x99, 0xf4, 0xd, 0xb8, 0x8c, 0x5, 0xa7, 0x28, 0x8, 0x98, 0x9, 0x68, 0xba, 0x41, 0x66, 0x1b, 0x8a, 0xa2, 0xb0, 0x4d, 0x59, 0x30, 0xa5, 0x94, 0xa3, 0x94, 0x52, 0x0, 0x6f, 0x53, 0x6f, 0x7c, 0x82, 0x16, 0xcc, 0x5a, 0x51, 0x14, 0xbd, 0x98, 0x79, 0x4c, 0x29, 0x72, 0xee, 0xac, 0x8c, 0xea, 0xac, 0xb9, 0x51, 0xa0, 0xce, 0xa, 0x44, 0x60, 0x46, 0xa4, 0x28, 0x2, 0x9b, 0x1, 0x2a, 0x5a, 0xa, 0x9a, 0x49, 0xa9, 0xe8, 0x79, 0x20, 0x33, 0x38, 0xaf, 0x68, 0xc5, 0x68, 0xc6, 0x95, 0xa2, 0xe7, 0x72, 0x67, 0x3d, 0x97, 0x52, 0x24, 0xcf, 0x66, 0x9e, 0x30, 0xa5, 0xef, 0x5a, 0x34, 0x6b, 0xdf, 0xa5, 0x14, 0xa4, 0x0, 0xb3, 0x42, 0x8c, 0xe5, 0x38, 0x37, 0xb4, 0x14, 0x3d, 0xd2, 0xda, 0xb4, 0x3d, 0xa2, 0x68, 0xe3, 0xc0, 0xcc, 0x35, 0x8a, 0x9e, 0x86, 0x4c, 0xa7, 0x15, 0x85, 0x9d, 0x6c, 0xb6, 0x13, 0x16, 0xe8, 0x54, 0x78, 0xbc, 0x8e, 0x60, 0x86, 0xd7, 0xd1, 0x17, 0xd3, 0x37, 0x6e, 0x48, 0x30, 0x4f, 0x70, 0x81, 0xbe, 0xed, 0x97, 0xd1, 0xfe, 0x6d, 0x44, 0xf7, 0xed, 0xa7, 0x63, 0x39, 0x79, 0x8c, 0xf6, 0xef, 0x8b, 0xe8, 0x61, 0xe6, 0x8d, 0x55, 0x5b, 0xae, 0x9e, 0x62, 0x3e, 0x1c, 0xd1, 0x3b, 0xf7, 0x9b, 0xc7, 0xfb, 0x9b, 0xab, 0x46, 0xcd, 0xab, 0x4b, 0xcd, 0xfd, 0x3b, 0x11, 0x1d, 0xe, 0x76, 0xf5, 0xc5, 0x2b, 0xe5, 0xf3, 0x67, 0x49, 0xcf, 0xcb, 0x2b, 0x8f, 0xea, 0xee, 0xe0, 0x10, 0xd1, 0xf0, 0xb2, 0x58, 0xb, 0x61, 0x75, 0xd6, 0x26, 0xcd, 0x56, 0x43, 0x58, 0x2b, 0x5e, 0x86, 0x88, 0x4e, 0x63, 0x33, 0x84, 0xf7, 0x1f, 0x26, 0xd5, 0x87, 0xf7, 0x61, 0x68, 0xc6, 0x29, 0xa2, 0x73, 0xdb, 0x5e, 0x2d, 0x57, 0x1f, 0xab, 0x56, 0xcb, 0xab, 0xed, 0x5c, 0xfe, 0xc4, 0x5d, 0xf1, 0x27, 0x1a, 0x8f, 0xba, 0x8d, 0xd7, 0xa0, 0x9a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char progress_bar_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0x27, 0x27, 0x27, 0xe1, 0x1d, 0x66, 0x4d, 0x0, 0x0, 0x0, 0xc, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xb7, 0x4a, 0xbe, 0x33, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x10, 0x95, 0xb2, 0xd, 0x2c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x44, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xc5, 0xcf, 0x31, 0x16, 0x0, 0x10, 0xc, 0x44, 0xc1, 0x4d, 0x84, 0x4, 0xc1, 0xfd, 0x6f, 0xab, 0xc9, 0x53, 0x70, 0x0, 0x53, 0x6e, 0xb5, 0x1f, 0x20, 0x4e, 0x12, 0x12, 0x13, 0x40, 0xb9, 0xa8, 0x5, 0x2d, 0x99, 0xc0, 0xb5, 0x75, 0xf, 0xbd, 0x55, 0x86, 0xe8, 0x98, 0x2b, 0xcc, 0xa1, 0x2, 0x31, 0x5f, 0x87, 0xdb, 0xbf, 0xe1, 0x3e, 0xf6, 0x5c, 0x7f, 0xe2, 0xee, 0xfc, 0xd, 0x60, 0x3b, 0xa, 0x1d, 0x9e, 0x6a, 0x29, 0x33, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0x43, 0x65, 0x7d, 0x95, 0x0, 0x0, 0x0, 0xc, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xb7, 0x4a, 0xbe, 0x33, 0x0, 0x0, 0x0, 0x35, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x9f, 0xe, 0x66, 0xb4, 0x33, 0x7a, 0xb4, 0x1b, 0x0, 0x19, 0x7f, 0x3b, 0x28, 0x64, 0xc0, 0xd, 0x84, 0x5b, 0x1, 0xb7, 0x14, 0xee, 0xc, 0x0, 0xcf, 0x9d, 0x26, 0xff, 0xba, 0xcb, 0x90, 0x39, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char progress_fill_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x26, 0x78, 0x80, 0xa6, 0xcf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x60, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x78, 0xc0, 0x8, 0x63, 0x38, 0x58, 0x7c, 0xde, 0xf8, 0x45, 0xc, 0xc2, 0xe6, 0x79, 0xc5, 0xeb, 0x7f, 0xe0, 0x4, 0x9a, 0x2, 0xe3, 0x97, 0x1f, 0xb9, 0xff, 0x70, 0x43, 0xd8, 0x2c, 0x5f, 0xf9, 0xbf, 0x9e, 0x15, 0x87, 0xb2, 0x61, 0xa, 0xbe, 0x88, 0xfd, 0x81, 0x1b, 0xfb, 0x87, 0xfb, 0xb, 0x37, 0x8c, 0xcd, 0x44, 0xc8, 0xd, 0x54, 0x54, 0xc0, 0xf3, 0x8a, 0xe5, 0x2b, 0x8c, 0xcd, 0xf2, 0x95, 0xe7, 0x15, 0x86, 0x2, 0x5e, 0x7f, 0xfe, 0xaf, 0xec, 0xc, 0x10, 0xc8, 0xff, 0x95, 0xd7, 0x9f, 0xe6, 0x1, 0x4c, 0x2, 0x0, 0x0, 0x68, 0x3f, 0x16, 0xd7, 0xea, 0x7c, 0xdd, 0x1a, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x4c, 0xc0, 0xc1, 0xc2, 0xf8, 0xa5, 0xfa, 0x7f, 0x8, 0x34, 0x7e, 0xe9, 0x60, 0x81, 0xa1, 0xc0, 0xf8, 0xa5, 0xca, 0x17, 0x85, 0xff, 0x10, 0xa8, 0xf2, 0xc5, 0xf8, 0x25, 0x86, 0x2, 0x75, 0xa0, 0x4, 0x1c, 0x2, 0x4d, 0xa1, 0xbf, 0x2, 0x4c, 0x47, 0x12, 0xf6, 0xe6, 0x20, 0x2, 0x0, 0x78, 0x21, 0x45, 0x61, 0x7f, 0xe2, 0xad, 0xaf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char radio_checked_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xa, 0x69, 0x4, 0xd4, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x16, 0x7c, 0xd1, 0xa8, 0x19, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x69, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0x8f, 0xdb, 0xe, 0xc0, 0x20, 0x8, 0x43, 0xdd, 0xc5, 0x3b, 0x9d, 0xa8, 0xec, 0xff, 0x7f, 0x75, 0x6a, 0x96, 0x2c, 0x8b, 0xf6, 0xad, 0x27, 0x14, 0x8a, 0x52, 0x2b, 0x69, 0x63, 0x9d, 0xb3, 0x46, 0xbf, 0x76, 0xf3, 0x21, 0x12, 0x40, 0x31, 0xf8, 0x7d, 0x0, 0x7f, 0x35, 0xdb, 0x45, 0x97, 0x1f, 0xf3, 0x81, 0x90, 0x38, 0x67, 0x4e, 0xa0, 0xd0, 0x53, 0x26, 0x22, 0x95, 0x2a, 0x52, 0x4b, 0x42, 0x34, 0xd, 0x58, 0x2, 0xd7, 0xbb, 0xa9, 0x32, 0xc8, 0x36, 0xe0, 0x80, 0x2c, 0x1d, 0x48, 0x6, 0xdc, 0xa, 0x4c, 0x91, 0x69, 0xe9, 0x74, 0x76, 0x2a, 0xa6, 0x8e, 0xaf, 0xfa, 0xb9, 0x7e, 0xee, 0xaf, 0x7, 0xb9, 0xfb, 0x8, 0xe7, 0x90, 0x1c, 0x65, 0x49, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x42, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xd1, 0xa7, 0xf5, 0xaa, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x4f, 0x55, 0x2, 0x43, 0x31, 0x8, 0x4b, 0xe8, 0x6a, 0xf7, 0xbf, 0xeb, 0xc, 0x9b, 0x6b, 0x1f, 0x9f, 0xc4, 0x89, 0xbf, 0xbb, 0x3f, 0x2a, 0x49, 0x64, 0xa6, 0x3e, 0x1e, 0x1c, 0x7c, 0x3e, 0xf2, 0x14, 0xb7, 0xc7, 0xac, 0xf1, 0x10, 0xa6, 0xe8, 0x1, 0x44, 0xad, 0x42, 0xb9, 0x33, 0x22, 0x43, 0x95, 0x68, 0x55, 0xa4, 0xdc, 0x1f, 0x1e, 0xa1, 0x67, 0xa2, 0x57, 0x96, 0x22, 0x0, 0xc2, 0x3d, 0xf5, 0x44, 0x8c, 0x8a, 0x5d, 0x21, 0x80, 0x74, 0x83, 0x1e, 0x97, 0xc7, 0x22, 0x59, 0x4c, 0xd7, 0xd8, 0xb5, 0x18, 0x4a, 0x7b, 0x57, 0x57, 0xdb, 0x1a, 0xf7, 0x77, 0x17, 0x3a, 0x56, 0x4e, 0x11, 0x6f, 0x82, 0x20, 0xde, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char radio_unchecked_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xff, 0xff, 0xff, 0xbd, 0x7d, 0x89, 0x66, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xe, 0x6f, 0xbd, 0x30, 0x4f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x4a, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x80, 0xb0, 0x8a, 0xf6, 0x54, 0x10, 0x2d, 0xb9, 0xfa, 0xcc, 0x99, 0x5d, 0x93, 0x80, 0x8c, 0xb9, 0x67, 0x80, 0xe0, 0x26, 0x3, 0x3, 0xeb, 0x1a, 0x10, 0xe3, 0x54, 0x0, 0x3, 0xdb, 0x1e, 0x10, 0xe3, 0x74, 0x2, 0x3, 0xfb, 0x19, 0x30, 0x28, 0x60, 0xe0, 0x80, 0x30, 0x1a, 0x10, 0xc, 0xb8, 0x14, 0x5c, 0x31, 0x5c, 0x3b, 0xdc, 0x40, 0x6, 0x4b, 0x90, 0x15, 0x53, 0x90, 0x2d, 0x85, 0x2, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xc4, 0xfc, 0x38, 0x7b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0x2b, 0x6e, 0xf2, 0xbf, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x2, 0x61, 0x15, 0xed, 0xa9, 0x20, 0x5a, 0x72, 0xf5, 0x99, 0x33, 0xbb, 0x26, 0x1, 0x19, 0x73, 0xcf, 0x0, 0xc1, 0x4d, 0x6, 0x6, 0xd6, 0x35, 0x20, 0xc6, 0xa9, 0x0, 0x6, 0xb6, 0x3d, 0x20, 0xc6, 0xe9, 0x4, 0x6, 0xf6, 0x33, 0x60, 0x50, 0xc0, 0xc0, 0x1, 0x61, 0x34, 0xc0, 0x19, 0x70, 0x29, 0xb8, 0x62, 0xb8, 0x76, 0x84, 0x81, 0xc, 0x96, 0x20, 0x2b, 0xa6, 0xc0, 0x2d, 0x45, 0x0, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xb4, 0x84, 0xb6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char reference_border_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xf, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xd1, 0xd1, 0xff, 0xb7, 0xb7, 0xff, 0x41, 0x41, 0xff, 0xff, 0xff, 0xd5, 0xfa, 0x24, 0x40, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x4, 0x8f, 0x68, 0xd9, 0x51, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x27, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x50, 0x32, 0x6, 0x3, 0x25, 0x6, 0x5, 0x6, 0x30, 0x60, 0x62, 0x30, 0x10, 0x4, 0x3, 0x66, 0x6, 0x3, 0x1, 0x90, 0x0, 0x23, 0x2d, 0x18, 0x30, 0x2b, 0xe0, 0x96, 0xc2, 0x9c, 0x1, 0x0, 0x5, 0x29, 0x7, 0xb, 0xf6, 0x43, 0xc2, 0xd4, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x2, 0x3, 0x0, 0x0, 0x0, 0x62, 0x9d, 0x17, 0xf2, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xd1, 0xd1, 0xff, 0xb7, 0xb7, 0xff, 0x41, 0x41, 0x2b, 0x2, 0x77, 0xea, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x25, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x58, 0xff, 0xff, 0xff, 0x2f, 0x86, 0x6, 0x6, 0x6, 0x26, 0x86, 0xa3, 0xa1, 0xa1, 0xc1, 0xc, 0x47, 0x18, 0x18, 0x84, 0x49, 0x22, 0xc0, 0xda, 0xc0, 0x6, 0x80, 0x8d, 0x2, 0x0, 0x36, 0x2b, 0x14, 0x3d, 0x85, 0x39, 0x85, 0x31, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x48, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xff, 0xff, 0xff, 0x34, 0x3f, 0xa6, 0x65, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x17, 0xb, 0xd6, 0x98, 0x8f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x5c, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0x8e, 0x49, 0xe, 0xc0, 0x20, 0xc, 0x3, 0x3, 0x61, 0x9, 0x3b, 0x61, 0xfb, 0xff, 0x53, 0x4b, 0x5b, 0x55, 0x15, 0x73, 0x1b, 0xc9, 0xb2, 0xd, 0x20, 0x24, 0x2a, 0xad, 0x15, 0x4a, 0x1, 0x20, 0x8c, 0x25, 0xc7, 0xec, 0xc8, 0x1a, 0x1, 0xd2, 0x87, 0xd6, 0xc7, 0xe8, 0x2d, 0x78, 0x9, 0x48, 0x6d, 0xae, 0xcd, 0x6c, 0x84, 0xa0, 0x62, 0x5f, 0xf, 0x3d, 0x2a, 0x48, 0x3c, 0x5e, 0x19, 0x9c, 0x4e, 0x39, 0x62, 0x47, 0x41, 0x2e, 0x5f, 0x75, 0xc9, 0x7b, 0xb4, 0x52, 0x64, 0x8e, 0x54, 0xcd, 0x7d, 0xe1, 0xbf, 0x73, 0x1, 0x30, 0x2f, 0x7, 0x53, 0x16, 0x34, 0xbd, 0xfa, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x14, 0xee, 0x69, 0x20, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x55, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8e, 0x45, 0x2, 0x80, 0x50, 0x10, 0x42, 0xc1, 0xee, 0xfb, 0x5f, 0xd4, 0xd6, 0xdf, 0xfd, 0x36, 0xd3, 0x3, 0x4, 0xd, 0x90, 0x6, 0xb2, 0x25, 0x39, 0xe0, 0xd2, 0xf9, 0xcb, 0x6a, 0x60, 0x6f, 0x27, 0xb7, 0xbc, 0x58, 0xb7, 0x53, 0x4d, 0x0, 0xf2, 0x3f, 0x5e, 0x36, 0x43, 0x5f, 0xc3, 0xf0, 0xdf, 0x17, 0xd7, 0xa6, 0xae, 0x60, 0x10, 0xff, 0x57, 0x16, 0xc5, 0x5a, 0xf1, 0x60, 0xe3, 0xe7, 0x5f, 0x37, 0x46, 0x74, 0xba, 0x9a, 0x16, 0xef, 0x37, 0x1c, 0x6f, 0x61, 0x47, 0x1, 0xa5, 0xc7, 0x32, 0x47, 0x38, 0x12, 0x92, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_down_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_down_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_left_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x2e, 0x28, 0xa3, 0x7b, 0xf7, 0x6e, 0x8, 0xa3, 0xe7, 0xcc, 0x19, 0xa8, 0x14, 0x9c, 0xd1, 0x7b, 0x17, 0xa6, 0xfd, 0x1d, 0x86, 0x81, 0x60, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0xcc, 0x4e, 0x3f, 0xd1, 0x4, 0x90, 0xbf, 0x60, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x2e, 0x28, 0xa3, 0x7b, 0xf7, 0x6e, 0x8, 0xa3, 0xe7, 0xcc, 0x19, 0xa8, 0x14, 0x9c, 0xd1, 0x7b, 0x17, 0xa6, 0xfd, 0x1d, 0x86, 0x81, 0x60, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0xcc, 0x4e, 0x3f, 0xd1, 0x4, 0x90, 0xbf, 0x60, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_left_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0x2a, 0x13, 0xff, 0x12, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x10, 0x95, 0xb2, 0xd, 0x2c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x85, 0xcf, 0xcb, 0xe, 0x80, 0x20, 0xc, 0x44, 0xd1, 0xa2, 0x96, 0x47, 0x7, 0xe4, 0xff, 0xff, 0x16, 0xdc, 0x90, 0xe, 0xc6, 0x78, 0x97, 0x27, 0x69, 0xd3, 0x8a, 0x4, 0x75, 0x85, 0x43, 0x62, 0xca, 0xae, 0x14, 0x45, 0x33, 0xa5, 0xdf, 0x50, 0xa, 0x83, 0x99, 0x11, 0xa0, 0xa2, 0x7a, 0x0, 0xd0, 0xe0, 0xa1, 0x3d, 0xd1, 0xc8, 0x3d, 0xe3, 0xa5, 0xbd, 0x6f, 0x30, 0xe5, 0xef, 0xb0, 0x5, 0xaf, 0xe7, 0x4e, 0x7e, 0xff, 0x1a, 0xb, 0x26, 0x7, 0xac, 0xd9, 0xa3, 0x51, 0xe3, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0x58, 0xf9, 0x63, 0x6a, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x42, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x9e, 0x3d, 0x10, 0x46, 0xf7, 0xee, 0xdb, 0x10, 0x46, 0xef, 0xdd, 0xbb, 0x50, 0xa9, 0x77, 0xef, 0xa0, 0x8c, 0xfe, 0x7f, 0x30, 0xed, 0xff, 0x81, 0xc, 0x4c, 0x93, 0x11, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfe, 0x97, 0x40, 0xa0, 0xa6, 0x84, 0xb1, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_right_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x18, 0x33, 0x61, 0x8c, 0x59, 0x2b, 0xa0, 0x8c, 0x5d, 0xab, 0xa0, 0x8c, 0xdd, 0xbb, 0x77, 0x40, 0x18, 0x67, 0xce, 0x9c, 0x80, 0x31, 0xa0, 0x52, 0x77, 0x6f, 0x40, 0x19, 0xef, 0x30, 0xc, 0x84, 0x30, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfd, 0x36, 0x40, 0x93, 0xf1, 0x83, 0x5f, 0xf2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x18, 0x33, 0x61, 0x8c, 0x59, 0x2b, 0xa0, 0x8c, 0x5d, 0xab, 0xa0, 0x8c, 0xdd, 0xbb, 0x77, 0x40, 0x18, 0x67, 0xce, 0x9c, 0x80, 0x31, 0xa0, 0x52, 0x77, 0x6f, 0x40, 0x19, 0xef, 0x30, 0xc, 0x84, 0x30, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfd, 0x36, 0x40, 0x93, 0xf1, 0x83, 0x5f, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_right_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0x59, 0x59, 0x59, 0x56, 0xec, 0x9e, 0xdc, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x11, 0xe2, 0xb5, 0x3d, 0xba, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x85, 0xcf, 0xcb, 0xe, 0x80, 0x30, 0x8, 0x44, 0x51, 0xaa, 0xd2, 0x7, 0xb4, 0xd2, 0xff, 0xff, 0xda, 0xea, 0x6e, 0x46, 0x63, 0xbc, 0xcb, 0x93, 0x40, 0x40, 0x24, 0x29, 0x94, 0x36, 0xc9, 0xa5, 0x42, 0x25, 0x8b, 0x56, 0x4a, 0xbf, 0xa0, 0xb5, 0x7, 0x98, 0x19, 0x83, 0x77, 0xef, 0xc, 0x3e, 0xdc, 0x11, 0xc6, 0x1d, 0xc2, 0x79, 0x45, 0x23, 0x11, 0xc1, 0x4b, 0xe7, 0xfc, 0x3b, 0xc, 0xe0, 0xf5, 0xdc, 0xce, 0xef, 0x1f, 0xb, 0xc, 0x30, 0x7, 0xaf, 0x1f, 0x5b, 0x76, 0x12, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0x2e, 0x3d, 0xb1, 0x1e, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xc8, 0x31, 0x16, 0x2, 0x20, 0x10, 0x43, 0xc1, 0xe4, 0x83, 0xdc, 0xff, 0xb8, 0x88, 0xf, 0x57, 0xb, 0x8b, 0x80, 0x53, 0xe, 0xf2, 0x23, 0x18, 0xc6, 0x68, 0x61, 0x74, 0xca, 0xa, 0x2e, 0x74, 0xf9, 0x85, 0xfd, 0x17, 0x5c, 0x81, 0xfb, 0x11, 0x2a, 0xaa, 0x65, 0x80, 0x20, 0xc3, 0x5f, 0xaf, 0x2b, 0x96, 0xce, 0x78, 0xea, 0x88, 0x39, 0x95, 0x91, 0x70, 0x29, 0x94, 0xd9, 0x6b, 0x87, 0xf5, 0xfe, 0x0, 0xc6, 0xa7, 0x1b, 0x66, 0x7b, 0x42, 0xf1, 0x14, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_up_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_button_up_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_grabber_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x60, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0x59, 0x61, 0x5b, 0x59, 0x61, 0x5a, 0x58, 0x60, 0x59, 0x57, 0x5f, 0x5a, 0x58, 0x60, 0x5a, 0x58, 0x60, 0x57, 0x56, 0x5e, 0x58, 0x56, 0x5e, 0x56, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x55, 0x53, 0x5b, 0x55, 0x53, 0x5b, 0x54, 0x53, 0x5b, 0x55, 0x54, 0x5c, 0x54, 0x52, 0x5a, 0x55, 0x53, 0x5b, 0x5a, 0x58, 0x60, 0x56, 0x54, 0x5c, 0x54, 0x53, 0x5a, 0x55, 0x53, 0x5b, 0x53, 0x51, 0x59, 0x52, 0x51, 0x59, 0x52, 0x50, 0x58, 0x51, 0x50, 0x58, 0x51, 0x4f, 0x57, 0x50, 0x4e, 0x56, 0x4f, 0x4d, 0x55, 0x50, 0x4f, 0x57, 0x54, 0x52, 0x5a, 0xff, 0xff, 0xff, 0xc7, 0x51, 0xc2, 0xf2, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2c, 0xb8, 0xf4, 0x2e, 0xf2, 0xb8, 0xf4, 0xf5, 0xf4, 0xf5, 0xb8, 0x2f, 0xf2, 0x2e, 0xb8, 0xf4, 0xb8, 0x66, 0xf6, 0xf7, 0x12, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1f, 0x5, 0xd, 0x10, 0xbd, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x50, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x7, 0x18, 0x99, 0x98, 0x85, 0x98, 0x18, 0x21, 0x6c, 0x16, 0x56, 0x61, 0x11, 0x11, 0x61, 0x56, 0x16, 0x30, 0x87, 0x4d, 0x54, 0xc, 0x8, 0x44, 0xd9, 0xc0, 0x1c, 0x76, 0x71, 0x9, 0x20, 0x10, 0xe7, 0x0, 0x73, 0x38, 0x25, 0xa5, 0x80, 0x40, 0x92, 0xb, 0xcc, 0xe1, 0x96, 0x90, 0x6, 0x2, 0x9, 0x6e, 0x30, 0x87, 0x87, 0x57, 0x4a, 0x46, 0x46, 0x96, 0x97, 0x7, 0x62, 0x1c, 0x1f, 0xbf, 0x80, 0x9c, 0x20, 0x1f, 0x5e, 0xdb, 0x1, 0x23, 0xfd, 0x4, 0x11, 0x2d, 0x48, 0xcb, 0xd2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x5d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0x59, 0x61, 0x5b, 0x59, 0x61, 0x5a, 0x58, 0x60, 0x59, 0x57, 0x5f, 0x5a, 0x58, 0x60, 0x5a, 0x58, 0x60, 0x57, 0x56, 0x5e, 0x58, 0x56, 0x5e, 0x56, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x55, 0x53, 0x5b, 0x55, 0x53, 0x5b, 0x54, 0x53, 0x5b, 0x55, 0x54, 0x5c, 0x54, 0x52, 0x5a, 0x55, 0x53, 0x5b, 0x5a, 0x58, 0x60, 0x56, 0x54, 0x5c, 0x54, 0x53, 0x5a, 0x55, 0x53, 0x5b, 0x53, 0x51, 0x59, 0x52, 0x51, 0x59, 0x52, 0x50, 0x58, 0x51, 0x50, 0x58, 0x51, 0x4f, 0x57, 0x50, 0x4e, 0x56, 0x4f, 0x4d, 0x55, 0x50, 0x4f, 0x57, 0x54, 0x52, 0x5a, 0xae, 0x55, 0xff, 0xf7, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2c, 0xb8, 0xf4, 0x2e, 0xf2, 0xb8, 0xf4, 0xf5, 0xf4, 0xf5, 0xb8, 0x2f, 0xf2, 0x2e, 0xb8, 0xf4, 0xb8, 0x66, 0xf6, 0xf7, 0x12, 0x0, 0x0, 0x0, 0x48, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x64, 0xc7, 0xb1, 0x11, 0x80, 0x40, 0x8, 0x45, 0x41, 0xff, 0x83, 0x2, 0xe, 0xfb, 0x2f, 0x13, 0xe2, 0xf3, 0x6, 0x12, 0x1d, 0x37, 0x5b, 0xae, 0x97, 0x5f, 0x84, 0xdd, 0x68, 0xe2, 0x1e, 0x41, 0xb8, 0x77, 0x58, 0x6, 0xb6, 0xe8, 0x88, 0xd1, 0xe1, 0x93, 0xad, 0x63, 0xab, 0xa3, 0x3a, 0xa3, 0x26, 0xa9, 0x4a, 0x52, 0xf9, 0xc, 0x62, 0xcf, 0xa7, 0x8f, 0x1f, 0x1e, 0xbd, 0xff, 0x84, 0xee, 0x2, 0x0, 0x54, 0x76, 0x10, 0x19, 0x1e, 0xd7, 0x1d, 0x9b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_grabber_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x97, 0xd0, 0xdf, 0x92, 0xcb, 0xdc, 0x84, 0xbb, 0xd4, 0x92, 0xca, 0xdc, 0x95, 0xd0, 0xdd, 0x83, 0xbb, 0xd3, 0x8b, 0xc8, 0xd7, 0x79, 0xb5, 0xcb, 0x78, 0xb4, 0xca, 0x73, 0xb0, 0xc7, 0x73, 0xb0, 0xc7, 0x7b, 0xc0, 0xcf, 0x79, 0xc5, 0xd1, 0x6b, 0xae, 0xc1, 0x75, 0xc6, 0xcf, 0x70, 0xbc, 0xca, 0x64, 0xa6, 0xbc, 0x71, 0xbc, 0xc9, 0x82, 0xba, 0xd4, 0x6a, 0xa2, 0xc6, 0x62, 0x9a, 0xc2, 0x61, 0x9a, 0xc1, 0x68, 0x9f, 0xc2, 0x5d, 0x92, 0xbb, 0x5c, 0x92, 0xb8, 0x58, 0x8d, 0xb6, 0x59, 0x8e, 0xb3, 0x56, 0x89, 0xb0, 0x5c, 0x91, 0xb2, 0x53, 0x84, 0xa9, 0x58, 0x8f, 0xae, 0x54, 0x83, 0xa4, 0x57, 0x8e, 0xad, 0x64, 0xa5, 0xba, 0xff, 0xff, 0xff, 0xbb, 0x65, 0x65, 0x27, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x25, 0xad, 0xf1, 0xad, 0x27, 0xef, 0xad, 0xf1, 0xf3, 0xf1, 0xf3, 0xad, 0x28, 0xef, 0x27, 0xad, 0xf2, 0xad, 0xcd, 0x8a, 0x27, 0xfe, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x23, 0x2a, 0x62, 0x6c, 0x3a, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x50, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x7, 0x18, 0x99, 0x98, 0x85, 0x59, 0x18, 0x21, 0x6c, 0x56, 0x36, 0x11, 0x51, 0x31, 0x11, 0x36, 0x56, 0x30, 0x87, 0x5d, 0x5c, 0x2, 0x8, 0xc4, 0xd9, 0xc1, 0x1c, 0xe, 0x49, 0x29, 0x20, 0x90, 0xe4, 0x4, 0x73, 0xb8, 0xa4, 0x65, 0x80, 0x40, 0x9a, 0x1b, 0xcc, 0xe1, 0x91, 0x95, 0x3, 0x2, 0x59, 0x1e, 0x30, 0x87, 0x97, 0x4f, 0x5e, 0x41, 0x41, 0x91, 0x8f, 0x17, 0x62, 0x1c, 0xbf, 0x80, 0xa0, 0x92, 0x10, 0x3f, 0x5e, 0xdb, 0x1, 0x41, 0x87, 0x4, 0x7d, 0x15, 0xc4, 0xfd, 0x6a, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x69, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x97, 0xd0, 0xdf, 0x92, 0xcb, 0xdc, 0x84, 0xbb, 0xd4, 0x92, 0xca, 0xdc, 0x95, 0xd0, 0xdd, 0x83, 0xbb, 0xd3, 0x8b, 0xc8, 0xd7, 0x79, 0xb5, 0xcb, 0x78, 0xb4, 0xca, 0x73, 0xb0, 0xc7, 0x73, 0xb0, 0xc7, 0x7b, 0xc0, 0xcf, 0x79, 0xc5, 0xd1, 0x6b, 0xae, 0xc1, 0x75, 0xc6, 0xcf, 0x70, 0xbc, 0xca, 0x64, 0xa6, 0xbc, 0x71, 0xbc, 0xc9, 0x82, 0xba, 0xd4, 0x6a, 0xa2, 0xc6, 0x62, 0x9a, 0xc2, 0x61, 0x9a, 0xc1, 0x68, 0x9f, 0xc2, 0x5d, 0x92, 0xbb, 0x5c, 0x92, 0xb8, 0x58, 0x8d, 0xb6, 0x59, 0x8e, 0xb3, 0x56, 0x89, 0xb0, 0x5c, 0x91, 0xb2, 0x53, 0x84, 0xa9, 0x58, 0x8f, 0xae, 0x54, 0x83, 0xa4, 0x57, 0x8e, 0xad, 0x64, 0xa5, 0xba, 0x17, 0x3b, 0xfc, 0x67, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x25, 0xad, 0xf1, 0xad, 0x27, 0xef, 0xad, 0xf1, 0xf3, 0xf1, 0xf3, 0xad, 0x28, 0xef, 0x27, 0xad, 0xf2, 0xad, 0xcd, 0x8a, 0x27, 0xfe, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x75, 0xc7, 0xa5, 0x1, 0x3, 0x1, 0x0, 0x4, 0xc1, 0xdd, 0xb, 0x9a, 0x60, 0xff, 0x3d, 0x6, 0x54, 0xe0, 0x59, 0x3d, 0x8f, 0x9b, 0xb0, 0x66, 0x3, 0x98, 0xdc, 0xff, 0x35, 0x20, 0xec, 0x3c, 0x6b, 0xf5, 0xae, 0xff, 0x6c, 0xda, 0xdc, 0x36, 0x31, 0xc7, 0x6f, 0xc9, 0x16, 0x8c, 0x40, 0x1d, 0xba, 0x64, 0x21, 0x42, 0xc0, 0x97, 0xc9, 0xe6, 0x25, 0x8, 0x5c, 0xf4, 0xf6, 0x2c, 0x5f, 0x8c, 0x39, 0x4c, 0x3, 0xfe, 0x9a, 0x10, 0x43, 0x82, 0xcf, 0x27, 0x93, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_grabber_pressed_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xd, 0xd7, 0x0, 0x0, 0xd, 0xd7, 0x1, 0x42, 0x28, 0x9b, 0x78, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0x66, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xcd, 0x91, 0xb1, 0xa, 0xc0, 0x20, 0x10, 0x43, 0x63, 0x71, 0xbf, 0x5f, 0x12, 0x9c, 0xfd, 0x1a, 0x3f, 0xcd, 0xa9, 0x83, 0xe0, 0x2f, 0x65, 0x2f, 0x9c, 0x8b, 0x83, 0x47, 0xed, 0x60, 0xbb, 0x34, 0xdb, 0x3d, 0x12, 0x48, 0x38, 0xa7, 0xaa, 0xd8, 0xd1, 0xb1, 0xe5, 0x7e, 0x13, 0xf0, 0xf3, 0xd1, 0x5a, 0xf3, 0x24, 0x23, 0x80, 0x34, 0x50, 0x11, 0x91, 0x1a, 0x42, 0xb8, 0x96, 0x1, 0x92, 0x51, 0x55, 0xf3, 0x84, 0x32, 0x49, 0x0, 0x38, 0x9f, 0x2a, 0x25, 0xdc, 0x65, 0xd8, 0xe7, 0xd1, 0x65, 0xe1, 0x31, 0xcc, 0x6c, 0x10, 0x91, 0x3a, 0x3a, 0x9b, 0xd1, 0xb3, 0xc7, 0xfd, 0xef, 0x71, 0x1d, 0x42, 0xe6, 0x21, 0x43, 0xf5, 0x2b, 0xd8, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x3a, 0xd8, 0xcf, 0xb2, 0xc1, 0x7d, 0xc3, 0x14, 0x20, 0x74, 0xdf, 0xcf, 0x82, 0x22, 0xb1, 0xc1, 0x7d, 0xfd, 0x2e, 0x8, 0xdc, 0xe0, 0x8e, 0x2a, 0x31, 0x5, 0x2e, 0x31, 0x85, 0x90, 0x4, 0xa6, 0x51, 0xb8, 0x2d, 0xa7, 0x36, 0x0, 0x0, 0x7b, 0xcd, 0x2b, 0x75, 0x45, 0x5e, 0xf8, 0x88, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char selection_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfb, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf6, 0xff, 0xf6, 0xf4, 0xff, 0x15, 0x15, 0x17, 0xff, 0x70, 0xc0, 0x21, 0x0, 0x0, 0x0, 0xe, 0x74, 0x52, 0x4e, 0x53, 0x6, 0xf, 0x16, 0x18, 0x2a, 0x3b, 0x40, 0x3c, 0x6, 0x3d, 0x44, 0x3e, 0x31, 0x25, 0x8, 0x3d, 0x16, 0xb4, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xe, 0x6f, 0xbd, 0x30, 0x4f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x6, 0x2, 0x23, 0x1, 0x6, 0x91, 0xb0, 0x34, 0x20, 0x48, 0x75, 0x64, 0x50, 0xef, 0x5c, 0x5, 0x4, 0x33, 0x8a, 0x18, 0xcc, 0xf6, 0xdc, 0x5, 0x82, 0xd3, 0xc9, 0xc, 0x66, 0x6b, 0x41, 0x8c, 0x5b, 0x94, 0x33, 0x60, 0x6, 0xc2, 0xad, 0x80, 0x5b, 0xa, 0x73, 0x6, 0x0, 0x45, 0x34, 0x48, 0x41, 0xa3, 0xc5, 0x91, 0x23, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfb, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf6, 0xff, 0xf6, 0xf4, 0xff, 0x15, 0x15, 0x17, 0xff, 0x70, 0xc0, 0x21, 0x0, 0x0, 0x0, 0xe, 0x74, 0x52, 0x4e, 0x53, 0x6, 0xf, 0x16, 0x18, 0x2a, 0x3b, 0x40, 0x3c, 0x6, 0x3d, 0x44, 0x3e, 0x31, 0x25, 0x8, 0x3d, 0x16, 0xb4, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x6, 0x2, 0x23, 0x1, 0x6, 0x91, 0xb0, 0x34, 0x20, 0x48, 0x75, 0x64, 0x50, 0xef, 0x5c, 0x5, 0x4, 0x33, 0x8a, 0x18, 0xcc, 0xf6, 0xdc, 0x5, 0x82, 0xd3, 0xc9, 0xc, 0x66, 0x6b, 0x41, 0x8c, 0x5b, 0x94, 0x33, 0x60, 0x6, 0xc2, 0xad, 0x80, 0x5b, 0xa, 0x73, 0x6, 0x0, 0x45, 0x34, 0x48, 0x41, 0xa3, 0xc5, 0x91, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char selection_oof_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0x15, 0x15, 0x17, 0xe9, 0x54, 0x1, 0x21, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x76, 0x1, 0x2, 0x23, 0x1, 0x6, 0xd1, 0xf4, 0xe, 0x20, 0x28, 0xb, 0x64, 0xd0, 0x5c, 0x7d, 0x6, 0x8, 0x76, 0x4d, 0x62, 0x70, 0xdf, 0xfb, 0xe, 0x8, 0x6e, 0x97, 0x30, 0x78, 0x9c, 0x3, 0x31, 0xde, 0xb4, 0x50, 0xca, 0x80, 0x1b, 0x8, 0xb7, 0x2, 0x6e, 0x29, 0xcc, 0x19, 0x0, 0x1a, 0x23, 0x52, 0x59, 0xa4, 0x2f, 0x3d, 0xa7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xaf, 0xdf, 0x90, 0xa5, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x2f, 0x33, 0x4, 0x32, 0xde, 0xce, 0x64, 0xf4, 0x68, 0x53, 0x0, 0x32, 0xfe, 0xcd, 0xa0, 0x90, 0x1, 0x37, 0x10, 0x6e, 0x5, 0xdc, 0x52, 0xb8, 0x33, 0x0, 0xcc, 0x7, 0x26, 0xff, 0x1f, 0x38, 0x23, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char spinbox_updown_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xcd, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xe5, 0x53, 0x31, 0xe, 0x82, 0x40, 0x10, 0x9c, 0x5d, 0x22, 0x3e, 0x80, 0x86, 0xc4, 0x0, 0xe1, 0xf, 0x16, 0x5a, 0x58, 0xf9, 0x5, 0xe3, 0x13, 0xd0, 0xc2, 0xc4, 0xcf, 0xd8, 0xf0, 0x5, 0xe3, 0x1f, 0x2c, 0x2c, 0x6c, 0xf8, 0x1, 0xc5, 0x72, 0x85, 0x9, 0xd, 0xf, 0x10, 0x43, 0xce, 0x86, 0x82, 0xe0, 0xe9, 0x19, 0x8d, 0x95, 0x53, 0xce, 0xce, 0x6e, 0x26, 0x99, 0x59, 0xe0, 0x97, 0x10, 0x91, 0x95, 0x52, 0x2a, 0x79, 0xa5, 0xa1, 0x67, 0x83, 0xa2, 0x28, 0xa6, 0x0, 0x8e, 0x0, 0x98, 0x99, 0xe7, 0x61, 0x18, 0x9e, 0xde, 0x3e, 0x20, 0x22, 0x3e, 0x11, 0x65, 0x0, 0x46, 0x2d, 0x55, 0x3a, 0x8e, 0x33, 0xe, 0x82, 0xe0, 0xd2, 0xd7, 0x72, 0x9f, 0xc8, 0xb2, 0x6c, 0x0, 0x60, 0xdf, 0x59, 0x6, 0x0, 0xbf, 0x69, 0x9a, 0x43, 0x9e, 0xe7, 0x43, 0xeb, 0x1, 0xcf, 0xf3, 0x76, 0x44, 0x34, 0x33, 0x18, 0x9b, 0xb8, 0xae, 0x9b, 0x9a, 0x1c, 0xff, 0x3b, 0x1e, 0x62, 0x14, 0x91, 0x94, 0x88, 0x8c, 0xe5, 0x21, 0xa2, 0x34, 0x8a, 0xa2, 0x75, 0x97, 0x7b, 0x48, 0xa1, 0xaa, 0xaa, 0x8d, 0xd6, 0xda, 0x54, 0x9a, 0x73, 0x5d, 0xd7, 0x5b, 0xab, 0x83, 0xd6, 0xc5, 0xe7, 0x45, 0x2, 0x80, 0x38, 0x8e, 0x4b, 0xad, 0xf5, 0x2, 0xc0, 0x15, 0xc0, 0x8d, 0x99, 0x97, 0xa6, 0x65, 0x2b, 0x94, 0x52, 0x89, 0xed, 0x99, 0xbe, 0xc6, 0x1d, 0x31, 0x1f, 0x40, 0xdc, 0x74, 0x8a, 0x5b, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0xdc, 0x4f, 0x7f, 0x98, 0x86, 0x47, 0xfa, 0x81, 0xe5, 0x83, 0x1f, 0xf, 0x7e, 0x3d, 0xb2, 0xc5, 0xa5, 0x5b, 0xe2, 0xc1, 0x93, 0x7, 0xff, 0x81, 0xf0, 0xf9, 0x63, 0x69, 0x2c, 0xd2, 0x67, 0x58, 0xef, 0x1f, 0x2, 0x4a, 0x42, 0xe0, 0xf1, 0xdb, 0xec, 0x98, 0xfa, 0x67, 0x2, 0x25, 0xe0, 0xf0, 0xe1, 0x2, 0x86, 0x41, 0x7, 0x30, 0x1d, 0x39, 0x3, 0xbf, 0x37, 0x8f, 0xdd, 0x66, 0x27, 0x29, 0xa0, 0x10, 0x4a, 0x2c, 0xa0, 0x41, 0x8d, 0x1b, 0x3c, 0x4c, 0x3, 0x46, 0x16, 0x69, 0x0, 0x0, 0x87, 0x2a, 0x58, 0xb5, 0x18, 0xe9, 0x80, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char submenu_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x7d, 0xca, 0x21, 0x12, 0x80, 0x20, 0x14, 0x45, 0xd1, 0xf7, 0x2d, 0x4, 0x36, 0x40, 0x63, 0xa8, 0xba, 0x1f, 0xbb, 0x9d, 0xe5, 0xb8, 0x0, 0xb3, 0xfb, 0xd1, 0xc, 0x8d, 0xd, 0x10, 0x48, 0xcf, 0x22, 0x6, 0xc7, 0xef, 0x6d, 0x77, 0xe6, 0x8, 0x0, 0xa4, 0x94, 0x88, 0x3b, 0x92, 0x4b, 0x8, 0x61, 0xeb, 0x3f, 0xe0, 0x95, 0x88, 0xac, 0x39, 0xe7, 0x49, 0x5, 0x0, 0x2c, 0xc9, 0xbd, 0x94, 0x62, 0x35, 0x0, 0x0, 0x63, 0x6b, 0x6d, 0xfd, 0x3, 0x4f, 0x1a, 0x38, 0x8d, 0x31, 0x51, 0x3, 0x55, 0x44, 0x66, 0xe7, 0x5c, 0xfd, 0x4, 0x24, 0xa3, 0xf7, 0xfe, 0xe8, 0x7f, 0x1, 0xe, 0xc2, 0x1e, 0x10, 0xa, 0xf0, 0x33, 0x4c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0xc0, 0xf0, 0xe0, 0x3f, 0x8, 0xde, 0x4f, 0x60, 0x0, 0x3, 0xb8, 0xc0, 0x83, 0x2f, 0xf, 0xb5, 0xe1, 0x2, 0x50, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xc0, 0xff, 0x87, 0xf3, 0x31, 0x4, 0x30, 0xb5, 0x60, 0x1a, 0x8a, 0x61, 0x2d, 0x0, 0xa6, 0x55, 0x4f, 0xb1, 0x91, 0xd6, 0xa7, 0xae, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0xaa, 0x8d, 0x23, 0x32, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x4, 0xff, 0x23, 0xff, 0x8b, 0xfc, 0x17, 0xf9, 0x1f, 0x49, 0xac, 0x10, 0x13, 0x3, 0x3, 0x61, 0x53, 0xb0, 0x98, 0x80, 0xc, 0x0, 0xa8, 0x3e, 0x18, 0x31, 0xbe, 0x78, 0xfc, 0x7a, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x19, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0xfe, 0x47, 0xfe, 0x17, 0x1, 0xc2, 0x48, 0xd2, 0x84, 0x10, 0x2, 0x84, 0xb9, 0x98, 0x0, 0x0, 0xbf, 0x67, 0x1d, 0x5, 0x89, 0x9b, 0x48, 0x90, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_behind_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x5a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x2e, 0x36, 0x43, 0x40, 0x4d, 0x0, 0x0, 0x0, 0x43, 0x40, 0x4c, 0x3e, 0x3c, 0x47, 0x3e, 0x3b, 0x46, 0x31, 0x2f, 0x38, 0x2d, 0x2b, 0x33, 0x3f, 0x3c, 0x47, 0x35, 0x32, 0x3b, 0x5b, 0xb0, 0x1, 0xb7, 0x0, 0x0, 0x0, 0x18, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0xc, 0x4, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x77, 0xf3, 0x7, 0xef, 0xd3, 0x51, 0x5e, 0xca, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1d, 0xeb, 0x3, 0x71, 0x91, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xb5, 0xcc, 0x49, 0xe, 0x80, 0x20, 0x10, 0x44, 0xd1, 0x2, 0x6c, 0x90, 0x49, 0x26, 0x27, 0xd4, 0xfb, 0x9f, 0x53, 0x63, 0x34, 0x2e, 0x58, 0xfb, 0x97, 0x2f, 0xa9, 0x2, 0x18, 0x17, 0x1d, 0x49, 0xa5, 0x24, 0x75, 0x82, 0x33, 0x80, 0xf5, 0xa4, 0x8d, 0x75, 0xde, 0x3b, 0x6b, 0x34, 0xf5, 0xc, 0x9c, 0x86, 0x10, 0x53, 0x2e, 0x25, 0xa7, 0x18, 0x6, 0xe2, 0x10, 0x3a, 0x8c, 0xd3, 0x5a, 0xaf, 0xd6, 0x69, 0xc, 0x5a, 0x60, 0x36, 0x71, 0xd9, 0xf6, 0xbb, 0x6d, 0x89, 0x66, 0x6, 0xd9, 0x74, 0xec, 0x4f, 0x47, 0xb2, 0x4, 0xe9, 0x72, 0x7d, 0xa1, 0x66, 0x27, 0xa1, 0x7c, 0xf9, 0xa0, 0x78, 0xd5, 0x42, 0x33, 0x69, 0x4e, 0xff, 0x80, 0x13, 0xce, 0x8, 0x12, 0xa9, 0x90, 0xd8, 0x47, 0x93, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x57, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x2e, 0x36, 0x43, 0x40, 0x4d, 0x0, 0x0, 0x0, 0x43, 0x40, 0x4c, 0x3e, 0x3c, 0x47, 0x3e, 0x3b, 0x46, 0x31, 0x2f, 0x38, 0x2d, 0x2b, 0x33, 0x3f, 0x3c, 0x47, 0x91, 0xf8, 0xc4, 0xb2, 0x0, 0x0, 0x0, 0x18, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0xc, 0x4, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x77, 0xf3, 0x7, 0xef, 0xd3, 0x51, 0x5e, 0xca, 0x0, 0x0, 0x0, 0x5a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0x8c, 0x35, 0x2, 0x80, 0x30, 0x10, 0x4, 0x6f, 0x73, 0xc4, 0x53, 0xf3, 0xff, 0x3f, 0xe2, 0xee, 0x4e, 0x9d, 0xe9, 0x56, 0x41, 0xd8, 0xa1, 0x69, 0x7, 0xd0, 0x43, 0x72, 0x19, 0x3d, 0x37, 0x10, 0x6c, 0x1f, 0x8d, 0x6a, 0x0, 0x2b, 0x25, 0xc1, 0x20, 0xa2, 0x69, 0x98, 0xba, 0xb6, 0x45, 0x9a, 0x2b, 0xbd, 0xe9, 0xd5, 0x69, 0xda, 0x0, 0xa9, 0x94, 0x9f, 0x68, 0x7, 0xc5, 0xd2, 0x50, 0x4a, 0x69, 0x71, 0x18, 0x63, 0xb3, 0x18, 0x7a, 0x71, 0x2e, 0xa3, 0xfd, 0x1b, 0xff, 0xc9, 0xff, 0x34, 0x86, 0x31, 0x3, 0x12, 0xb2, 0x4c, 0x6a, 0xfb, 0x60, 0xc7, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_close_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x5f, 0x4a, 0xc4, 0x30, 0x10, 0x87, 0xbf, 0xb1, 0xb9, 0xc2, 0x16, 0x7c, 0x6b, 0xc1, 0xa2, 0x85, 0x7a, 0x4, 0x2d, 0xfe, 0x39, 0xc4, 0x9e, 0x70, 0x4f, 0x61, 0xc5, 0x3d, 0x83, 0x5, 0x95, 0x4, 0xd2, 0x37, 0x5, 0x8f, 0x90, 0x94, 0xf1, 0xc5, 0x4a, 0x76, 0xcd, 0x22, 0xf8, 0xa2, 0xf3, 0x38, 0xc3, 0xef, 0x9b, 0xe4, 0x4b, 0xe0, 0x5f, 0x95, 0xf7, 0x7e, 0xed, 0x9c, 0x2b, 0xf, 0xcd, 0x9d, 0x73, 0xa5, 0xf7, 0x7e, 0x9d, 0xf6, 0x8e, 0xd2, 0xb0, 0x88, 0x6c, 0x8c, 0x31, 0x43, 0xe, 0xe2, 0x9c, 0x2b, 0x8d, 0x31, 0x83, 0x88, 0x6c, 0x52, 0xc8, 0x17, 0x20, 0xc6, 0x38, 0xa8, 0xea, 0x8, 0x74, 0xc6, 0x98, 0xed, 0x34, 0x4d, 0xc7, 0xcb, 0xcc, 0x5a, 0xbb, 0x2a, 0x8a, 0xe2, 0xe, 0xe8, 0x80, 0x17, 0xe0, 0x61, 0x99, 0x49, 0xba, 0xc5, 0x5a, 0xbb, 0xfa, 0xdc, 0x72, 0xe, 0x3c, 0x3, 0xd7, 0x21, 0x84, 0x98, 0xf6, 0x54, 0xf5, 0xaa, 0xae, 0xeb, 0xb7, 0x2c, 0x60, 0x1f, 0x22, 0x22, 0x56, 0x55, 0x23, 0xd0, 0xe6, 0xc2, 0x59, 0x40, 0x2, 0xd9, 0x8a, 0x48, 0xbb, 0x28, 0x50, 0xd5, 0x8b, 0xfd, 0xf0, 0x8e, 0x83, 0x9f, 0x4a, 0x44, 0xb2, 0xcb, 0xbe, 0x1, 0x92, 0x2b, 0xb4, 0xaa, 0x6a, 0x81, 0x27, 0xe0, 0x4, 0xb8, 0x4f, 0xc5, 0x66, 0x1, 0x19, 0x89, 0x97, 0x21, 0x84, 0x5e, 0x55, 0x1f, 0x81, 0xb3, 0x1c, 0x44, 0xe, 0x85, 0x53, 0x61, 0xb9, 0xd7, 0xa9, 0xaa, 0xea, 0x75, 0xe7, 0x4, 0xc6, 0x98, 0x1b, 0x11, 0xe9, 0x80, 0x31, 0xc6, 0xd8, 0xa7, 0xc2, 0x9a, 0xa6, 0x79, 0x9f, 0xe7, 0xf9, 0x16, 0x18, 0x81, 0x53, 0x55, 0xed, 0xb3, 0xa2, 0x7e, 0xf3, 0x95, 0xff, 0xbe, 0x3e, 0x0, 0xbd, 0x2c, 0x93, 0xec, 0xb, 0xe5, 0x4f, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x90, 0x1, 0x6, 0xc0, 0x30, 0xc, 0x45, 0x77, 0x89, 0xd5, 0x76, 0xb3, 0x9e, 0x7b, 0x65, 0x63, 0xd, 0xf9, 0xbb, 0x48, 0x3b, 0xb3, 0x92, 0x54, 0x42, 0xb1, 0x5, 0x88, 0xf7, 0xc8, 0xcf, 0x9f, 0xfe, 0x1a, 0x8e, 0x14, 0xf4, 0x4e, 0x81, 0x63, 0x87, 0x51, 0x90, 0x28, 0x8, 0x46, 0x42, 0x51, 0x4a, 0x9e, 0x79, 0x43, 0xc5, 0x81, 0x55, 0x6f, 0xbc, 0x34, 0xdc, 0x2b, 0x2e, 0x16, 0xe5, 0x3a, 0xb1, 0xb, 0xb6, 0xca, 0x3, 0x2b, 0xb2, 0xc2, 0xbe, 0xf0, 0x66, 0x71, 0x4f, 0x70, 0x3b, 0x61, 0x14, 0x89, 0x26, 0x71, 0x5d, 0x6c, 0x9f, 0x1e, 0x17, 0x35, 0xae, 0xfa, 0xeb, 0xdc, 0x62, 0xc3, 0x84, 0x2d, 0x77, 0x22, 0xda, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_container_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0xff, 0xff, 0xff, 0xe5, 0x37, 0x10, 0x78, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x2d, 0xcd, 0xda, 0x41, 0x3d, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x93, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x47, 0x12, 0x82, 0x40, 0x10, 0x5, 0xd0, 0x9e, 0xc8, 0x44, 0x92, 0x22, 0x41, 0x54, 0x44, 0x40, 0x14, 0xef, 0x7f, 0x3e, 0x7, 0x8a, 0xea, 0x85, 0xbe, 0xe5, 0xaf, 0xea, 0xf0, 0x1, 0x8, 0x65, 0x5c, 0xc8, 0x40, 0x70, 0x46, 0x9, 0x0, 0x89, 0x94, 0x36, 0xd6, 0x79, 0xef, 0xac, 0xd1, 0x2a, 0x22, 0x40, 0x55, 0x9c, 0x14, 0xa7, 0x4d, 0x91, 0xc4, 0x8a, 0x2, 0xd3, 0x69, 0x59, 0xd5, 0x9b, 0xaa, 0x4c, 0x35, 0x3, 0x6e, 0x9a, 0xfa, 0xbc, 0xab, 0x1b, 0xc3, 0x41, 0xd8, 0xf6, 0x82, 0x5a, 0x2b, 0x40, 0xba, 0xeb, 0xd, 0x5d, 0x9d, 0x4, 0xe9, 0xbb, 0x3b, 0xea, 0xfc, 0x1a, 0xf4, 0xf, 0xd4, 0xaf, 0x81, 0x1b, 0x46, 0x34, 0x84, 0x11, 0x61, 0xa7, 0x27, 0x9a, 0xc2, 0x52, 0x6e, 0xe6, 0x17, 0x9a, 0xc3, 0x59, 0xa6, 0xb3, 0xf1, 0xbd, 0x1b, 0xb3, 0xf0, 0x18, 0x55, 0xf9, 0x61, 0xf9, 0x6c, 0x96, 0x63, 0x1e, 0x5e, 0xff, 0x2b, 0xf7, 0x5b, 0xff, 0xb, 0x69, 0x5a, 0x14, 0xfa, 0x84, 0xf6, 0xc2, 0x8, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x14, 0x4, 0xd1, 0x2e, 0x1c, 0xee, 0x7f, 0xca, 0xd1, 0xed, 0x28, 0x8d, 0x4b, 0x92, 0x5a, 0xbe, 0xe8, 0x2f, 0xc4, 0x9c, 0x24, 0xcf, 0x15, 0x54, 0xab, 0x78, 0xee, 0x53, 0x30, 0x4a, 0x85, 0xa6, 0xfc, 0xf1, 0x87, 0x11, 0xb2, 0x9a, 0x15, 0x9a, 0x37, 0x13, 0x74, 0xce, 0xb4, 0xd4, 0x77, 0xcb, 0xe, 0xb4, 0x96, 0x99, 0x10, 0x34, 0x81, 0x42, 0x50, 0x21, 0x9d, 0x41, 0x23, 0xf8, 0xc, 0x56, 0xe1, 0x10, 0x9c, 0x40, 0x4e, 0xfe, 0x6e, 0x72, 0x96, 0x7e, 0xd7, 0xdf, 0x3f, 0xb3, 0x79, 0x90, 0xcd, 0xf1, 0xc4, 0x26, 0x1e, 0x8e, 0x78, 0xfc, 0x1, 0xf5, 0x61, 0x3f, 0x44, 0xe8, 0xf1, 0xdd, 0xba, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_current_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x9c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0x35, 0x32, 0x3b, 0x59, 0xdd, 0xd3, 0xff, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x33, 0x37, 0xd5, 0x7c, 0x5e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xa2, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x45, 0xcd, 0xd9, 0x12, 0x82, 0x30, 0xc, 0x40, 0xd1, 0x0, 0x2d, 0x4b, 0x5b, 0x36, 0x59, 0x44, 0x44, 0x44, 0xa4, 0x68, 0x59, 0x54, 0xfc, 0xff, 0x8f, 0x33, 0x30, 0x4c, 0x3d, 0x93, 0xa7, 0x3b, 0x93, 0x4, 0xc0, 0x30, 0x2d, 0x42, 0x6d, 0x44, 0x89, 0x65, 0x1a, 0x0, 0x86, 0xe3, 0x7a, 0x8c, 0xb, 0xdf, 0x17, 0x9c, 0x79, 0xae, 0x63, 0x80, 0xe9, 0x6, 0x61, 0x7c, 0xd8, 0xc4, 0x61, 0xe0, 0x9a, 0x60, 0x79, 0x51, 0x92, 0x66, 0x9b, 0x34, 0x89, 0x3c, 0xb, 0x8, 0xcb, 0xb3, 0xe3, 0x2e, 0xcb, 0x19, 0x1, 0xca, 0x8b, 0x93, 0x56, 0x70, 0xa, 0xb6, 0x28, 0xcf, 0x5a, 0x29, 0x6c, 0xb0, 0xfd, 0xea, 0xa2, 0x55, 0xfe, 0x1a, 0xea, 0xab, 0x56, 0xaf, 0x41, 0x34, 0x37, 0xad, 0xc1, 0x15, 0xca, 0xdb, 0xbb, 0xd6, 0xe2, 0x51, 0xc2, 0xba, 0x7f, 0xe8, 0xf0, 0x2d, 0x6, 0x29, 0xfb, 0x5e, 0xca, 0xc7, 0x53, 0xca, 0x3d, 0xa8, 0x61, 0x50, 0xc3, 0xa8, 0xc6, 0x41, 0xed, 0x61, 0x9a, 0xa6, 0x19, 0xbd, 0xe6, 0xf7, 0x1e, 0x3e, 0xcb, 0x82, 0x83, 0xbe, 0x18, 0x7e, 0xa1, 0xe5, 0x17, 0x1f, 0xcf, 0x5d, 0x82, 0x6b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0xd7, 0x41, 0xa4, 0x19, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x60, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xca, 0x85, 0xd, 0xc0, 0x40, 0x14, 0xc3, 0x50, 0x27, 0xf7, 0xd5, 0xfd, 0xd7, 0x2d, 0xa6, 0x4c, 0x16, 0x3f, 0xb9, 0xd0, 0x11, 0x90, 0xa3, 0x52, 0x77, 0x49, 0x8e, 0x86, 0xd2, 0x26, 0x16, 0x7b, 0x59, 0x32, 0x68, 0x3, 0x37, 0x5d, 0xe0, 0x59, 0x3b, 0x74, 0x31, 0x67, 0x4b, 0x3b, 0xf, 0x71, 0xe5, 0xe8, 0xf, 0xec, 0xc0, 0x1f, 0x28, 0xf8, 0x2, 0x14, 0xf9, 0x42, 0xa8, 0xfc, 0x21, 0x3b, 0xe4, 0x1, 0x6f, 0x0, 0x18, 0x11, 0xac, 0x99, 0xc0, 0xe, 0x25, 0x22, 0x2d, 0x76, 0xc6, 0x13, 0x1a, 0x8, 0xac, 0x78, 0xfc, 0x1c, 0x70, 0x30, 0x2b, 0xba, 0xe9, 0x31, 0x70, 0xc1, 0x7f, 0x3b, 0x77, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_menu_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x80, 0x81, 0x81, 0x11, 0x5d, 0xe0, 0xc1, 0x83, 0x7, 0xff, 0xf1, 0x69, 0x50, 0x50, 0x50, 0x40, 0xd1, 0xc3, 0x44, 0xa9, 0xb, 0xa8, 0x6f, 0x0, 0x23, 0x23, 0x63, 0x3c, 0x3, 0x3, 0xc3, 0x57, 0x2c, 0x6a, 0xbf, 0x33, 0x32, 0x32, 0xa6, 0x63, 0xa8, 0xc7, 0x66, 0xea, 0xfd, 0xfb, 0xf7, 0x35, 0x18, 0x18, 0x18, 0x56, 0x31, 0x32, 0x32, 0xea, 0x42, 0x85, 0x6e, 0x30, 0x33, 0x33, 0x87, 0xc9, 0xca, 0xca, 0x5e, 0x26, 0xca, 0x0, 0x6, 0x6, 0x6, 0x86, 0x17, 0x2f, 0x5e, 0x70, 0xff, 0xfc, 0xf9, 0x73, 0xa, 0x3, 0x3, 0x3, 0x3, 0x3b, 0x3b, 0x7b, 0x8e, 0x84, 0x84, 0x4, 0x36, 0x57, 0xd, 0x2, 0x0, 0x0, 0x67, 0xf2, 0x14, 0xc2, 0xc2, 0xbe, 0xf5, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_menu_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x80, 0x81, 0x81, 0x11, 0x5d, 0xe0, 0xc1, 0x83, 0x7, 0xff, 0xf1, 0x69, 0x50, 0x50, 0x50, 0x40, 0xd1, 0xc3, 0x44, 0xa9, 0xb, 0xa8, 0x6f, 0x0, 0x23, 0x23, 0x63, 0x3c, 0x3, 0x3, 0xc3, 0x57, 0x2c, 0x6a, 0xbf, 0x33, 0x32, 0x32, 0xa6, 0x63, 0xa8, 0xc7, 0x66, 0xea, 0xfd, 0xfb, 0xf7, 0x35, 0x18, 0x18, 0x18, 0x56, 0x31, 0x32, 0x32, 0xea, 0x42, 0x85, 0x6e, 0x30, 0x33, 0x33, 0x87, 0xc9, 0xca, 0xca, 0x5e, 0x26, 0xca, 0x0, 0x6, 0x6, 0x6, 0x86, 0x17, 0x2f, 0x5e, 0x70, 0xff, 0xfc, 0xf9, 0x73, 0xa, 0x3, 0x3, 0x3, 0x3, 0x3b, 0x3b, 0x7b, 0x8e, 0x84, 0x84, 0x4, 0x36, 0x57, 0xd, 0x2, 0x0, 0x0, 0x67, 0xf2, 0x14, 0xc2, 0xc2, 0xbe, 0xf5, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char toggle_off_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x7a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x2d, 0x26, 0x2c, 0x4d, 0x2b, 0x37, 0x63, 0x2f, 0x3f, 0x6e, 0x31, 0x43, 0x71, 0x32, 0x44, 0x6c, 0x31, 0x42, 0x51, 0x2c, 0x39, 0x47, 0x2a, 0x35, 0x66, 0x30, 0x40, 0x4d, 0x2b, 0x38, 0x32, 0x26, 0x2e, 0x26, 0x25, 0x2a, 0x2e, 0x25, 0x2c, 0x3c, 0x28, 0x31, 0x52, 0x2c, 0x39, 0x68, 0x30, 0x40, 0x27, 0x25, 0x2a, 0x50, 0x2c, 0x38, 0x5f, 0x2e, 0x3d, 0x35, 0x27, 0x2f, 0x38, 0x27, 0x30, 0x5e, 0x2e, 0x3d, 0x43, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x44, 0x2a, 0x34, 0x2b, 0x26, 0x2c, 0x64, 0x2f, 0x3f, 0x36, 0x27, 0x30, 0x37, 0x27, 0x30, 0x66, 0x2f, 0x40, 0x2c, 0x26, 0x2c, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x97, 0xb0, 0x86, 0xb4, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0x8, 0x17, 0x35, 0x86, 0xf3, 0x7, 0x3a, 0xb4, 0xb9, 0xb, 0x28, 0x8a, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xe6, 0x37, 0xf, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xe5, 0x7c, 0xf3, 0x66, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6b, 0x52, 0x65, 0xa5, 0x98, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x2, 0x47, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x55, 0xfb, 0x5b, 0x93, 0x50, 0x18, 0x96, 0x3, 0xc, 0x48, 0x60, 0xde, 0x70, 0x9b, 0x43, 0x37, 0x75, 0xa6, 0x9b, 0xb5, 0xad, 0x56, 0x59, 0x99, 0xe9, 0xc6, 0x39, 0xb3, 0x56, 0x59, 0xcd, 0x4c, 0xbb, 0xd9, 0x3d, 0xdb, 0xd, 0x74, 0xa6, 0xa3, 0xdb, 0xff, 0x1e, 0x70, 0x68, 0x6e, 0xc0, 0xe0, 0xe9, 0xe9, 0x97, 0x7a, 0x79, 0x9e, 0x3, 0xf, 0x7c, 0xdf, 0xcb, 0x7b, 0xbe, 0xf3, 0x5d, 0x86, 0x86, 0xfe, 0x21, 0x10, 0x80, 0x24, 0xa9, 0x40, 0x90, 0x24, 0x20, 0x3c, 0xdd, 0x1, 0x45, 0x87, 0x18, 0x96, 0x3b, 0x17, 0x0, 0x8e, 0x65, 0x42, 0x34, 0x5, 0xdc, 0x7f, 0xa7, 0x86, 0x59, 0x5e, 0x10, 0xc3, 0x23, 0xa3, 0x63, 0xbe, 0x18, 0x1d, 0x9, 0x8b, 0x2, 0xcf, 0xe, 0x53, 0xe, 0x15, 0x60, 0x7c, 0x42, 0x9a, 0x8c, 0x44, 0x63, 0x53, 0xc5, 0x52, 0x0, 0x8a, 0x53, 0xb1, 0x68, 0x64, 0x52, 0x9a, 0x18, 0xef, 0x13, 0x1, 0xe2, 0xf2, 0xf4, 0x4c, 0x42, 0x81, 0x10, 0x21, 0x84, 0xed, 0x90, 0x9, 0x88, 0xca, 0xc8, 0x93, 0x24, 0x31, 0x33, 0x2d, 0xc7, 0x7b, 0x18, 0x88, 0x24, 0x37, 0x3b, 0xa7, 0xc0, 0xcd, 0x3b, 0x77, 0x2b, 0xf7, 0x30, 0xee, 0x3f, 0xd8, 0xb4, 0x58, 0xca, 0x70, 0x80, 0x8e, 0xb9, 0x59, 0x2e, 0x49, 0x9c, 0xed, 0x9f, 0x11, 0xe6, 0x15, 0xb4, 0xf5, 0xf0, 0xd1, 0xe3, 0xaa, 0xf5, 0xb9, 0xba, 0xfd, 0x64, 0xe7, 0xe9, 0xd6, 0xae, 0xa5, 0x64, 0xd0, 0x4e, 0xe6, 0x5, 0xa6, 0x1b, 0x7, 0x90, 0x5a, 0x38, 0xaf, 0xa0, 0xbd, 0x67, 0xcf, 0x7b, 0x2d, 0x5e, 0xbc, 0xdc, 0xdb, 0xf5, 0x8d, 0xc5, 0xe2, 0x42, 0xea, 0xf7, 0x26, 0x28, 0x59, 0x5c, 0x82, 0xaf, 0xf6, 0xb7, 0xfb, 0x2d, 0x5e, 0xef, 0xbf, 0xa9, 0xfa, 0x31, 0x2c, 0xa5, 0xe5, 0xc, 0x96, 0x40, 0xd0, 0xfc, 0x32, 0x7c, 0xfb, 0xee, 0xbd, 0xd3, 0xe2, 0xc3, 0xc7, 0x4f, 0xbe, 0xe7, 0xb1, 0xcc, 0xd3, 0x98, 0x0, 0x84, 0x84, 0xb, 0xf0, 0x60, 0xc7, 0x6d, 0xf1, 0xf9, 0xc0, 0x7e, 0xa8, 0xd5, 0x1b, 0xcd, 0x56, 0x49, 0x6d, 0x18, 0xb0, 0x16, 0xcd, 0x7a, 0x7b, 0x31, 0x9b, 0xc3, 0x7b, 0x20, 0x19, 0x31, 0x86, 0xe, 0x8f, 0xdc, 0x4, 0x47, 0x87, 0xf6, 0x43, 0xfb, 0xb8, 0xf6, 0xa5, 0x51, 0x53, 0x4d, 0x47, 0xd5, 0xf6, 0x36, 0x90, 0x4f, 0x33, 0x24, 0x26, 0x60, 0x2f, 0x5d, 0x46, 0x27, 0xa7, 0x6e, 0x82, 0xd3, 0x13, 0x5b, 0x80, 0xe9, 0x74, 0xdc, 0x51, 0x75, 0x93, 0x40, 0xef, 0x12, 0x14, 0xb, 0x2c, 0x85, 0x9, 0xe4, 0x2b, 0xa, 0xaa, 0x78, 0x4, 0xac, 0x5a, 0xc1, 0x77, 0x55, 0x37, 0x96, 0xaf, 0x75, 0xb5, 0xdd, 0x6e, 0x6b, 0xd6, 0x62, 0x7f, 0xbf, 0x2a, 0xdb, 0x4, 0x6c, 0x58, 0xf1, 0x55, 0xa0, 0x99, 0xa, 0xea, 0xdf, 0x54, 0xd3, 0x53, 0x6d, 0x7b, 0x28, 0x60, 0xc4, 0x6b, 0xd0, 0x37, 0x6, 0x7a, 0xa7, 0xa4, 0x35, 0x5b, 0x4e, 0x82, 0x6e, 0xc, 0x40, 0x28, 0x1b, 0x70, 0xa, 0x6a, 0x53, 0x6f, 0xd6, 0x4b, 0x4e, 0x82, 0xee, 0x29, 0x18, 0x79, 0xb0, 0x12, 0x90, 0x7, 0x5a, 0xe7, 0xbb, 0x11, 0xcb, 0x96, 0x66, 0x2f, 0x18, 0x2b, 0x92, 0x9d, 0x7, 0x66, 0x26, 0x5e, 0x47, 0x7f, 0x91, 0x89, 0x66, 0x2d, 0x2c, 0xfe, 0x79, 0x2d, 0xdc, 0x38, 0xab, 0x5, 0xef, 0x6a, 0xfc, 0xe1, 0xef, 0xdf, 0x5b, 0x8d, 0x66, 0x3f, 0xb8, 0xb9, 0xaa, 0xc0, 0x9f, 0xce, 0x7e, 0xe0, 0xe3, 0xbf, 0x7a, 0xab, 0xa7, 0x1f, 0x98, 0x1d, 0x89, 0x13, 0xd6, 0x6e, 0xc3, 0x32, 0xc4, 0xd, 0x9, 0xd9, 0x80, 0xc6, 0xe5, 0xe9, 0x9f, 0x58, 0x13, 0xb8, 0x78, 0x7f, 0x4f, 0x4b, 0x32, 0x92, 0x18, 0x89, 0xe6, 0x3, 0x5b, 0xa2, 0xf1, 0xf3, 0x7c, 0x34, 0x22, 0x4a, 0x4c, 0xd2, 0xd1, 0x98, 0x9, 0x2a, 0xc5, 0xf2, 0xd9, 0x74, 0x61, 0x7d, 0x2c, 0x0, 0xeb, 0x85, 0x74, 0x96, 0x67, 0x53, 0x94, 0x6b, 0x36, 0x10, 0x20, 0x43, 0xe7, 0x36, 0xe4, 0xe0, 0xb9, 0x20, 0x6f, 0xe4, 0xe8, 0x8c, 0xf7, 0x6c, 0x31, 0x26, 0x53, 0xf0, 0x60, 0x32, 0x46, 0xd3, 0x80, 0xc9, 0xf4, 0xff, 0xe2, 0x17, 0x82, 0xde, 0x40, 0xde, 0x2d, 0xc3, 0x2a, 0xca, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x7a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x2d, 0x26, 0x2c, 0x4d, 0x2b, 0x37, 0x63, 0x2f, 0x3f, 0x6e, 0x31, 0x43, 0x71, 0x32, 0x44, 0x6c, 0x31, 0x42, 0x51, 0x2c, 0x39, 0x47, 0x2a, 0x35, 0x66, 0x30, 0x40, 0x4d, 0x2b, 0x38, 0x32, 0x26, 0x2e, 0x26, 0x25, 0x2a, 0x2e, 0x25, 0x2c, 0x3c, 0x28, 0x31, 0x52, 0x2c, 0x39, 0x68, 0x30, 0x40, 0x27, 0x25, 0x2a, 0x50, 0x2c, 0x38, 0x5f, 0x2e, 0x3d, 0x35, 0x27, 0x2f, 0x38, 0x27, 0x30, 0x5e, 0x2e, 0x3d, 0x43, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x44, 0x2a, 0x34, 0x2b, 0x26, 0x2c, 0x64, 0x2f, 0x3f, 0x36, 0x27, 0x30, 0x37, 0x27, 0x30, 0x66, 0x2f, 0x40, 0x2c, 0x26, 0x2c, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x97, 0xb0, 0x86, 0xb4, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0x8, 0x17, 0x35, 0x86, 0xf3, 0x7, 0x3a, 0xb4, 0xb9, 0xb, 0x28, 0x8a, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xe6, 0x37, 0xf, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xe5, 0x7c, 0xf3, 0x66, 0x0, 0x0, 0x2, 0x29, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x3, 0x93, 0x24, 0x4b, 0x14, 0x85, 0x5f, 0xb9, 0xaa, 0x6d, 0x8e, 0x6d, 0xdb, 0x73, 0x2b, 0xb3, 0xe7, 0xad, 0x6d, 0xab, 0xdd, 0x63, 0xe3, 0xbf, 0x6f, 0x67, 0x65, 0xbb, 0xb4, 0xbb, 0x81, 0xc5, 0x97, 0x11, 0x27, 0x78, 0x4f, 0xea, 0xe2, 0xbf, 0x3f, 0x9, 0x86, 0xe5, 0x38, 0xde, 0x16, 0x8e, 0x63, 0x19, 0xc3, 0x70, 0x96, 0x17, 0x44, 0x49, 0x56, 0x1c, 0x36, 0x28, 0xb2, 0x24, 0xa, 0x3c, 0xab, 0xdf, 0x9d, 0x77, 0xca, 0x2e, 0xb7, 0xc7, 0xeb, 0xf3, 0x7, 0x2c, 0xf1, 0xfb, 0xbc, 0x1e, 0xb7, 0x4b, 0x76, 0xf2, 0x2d, 0xa7, 0x60, 0x83, 0xa1, 0x70, 0x24, 0x1a, 0x8b, 0x27, 0xb6, 0xc1, 0x86, 0xed, 0x44, 0x3c, 0x16, 0x8d, 0x84, 0x43, 0x41, 0xb6, 0x29, 0x3e, 0xd9, 0xd6, 0xde, 0xd1, 0xa9, 0x22, 0x84, 0x31, 0x6, 0xd, 0x4c, 0x40, 0x38, 0x85, 0xd, 0x4d, 0x3a, 0x3b, 0xda, 0xdb, 0x92, 0xd, 0xe, 0x4c, 0x97, 0xd2, 0xdd, 0xa3, 0xa2, 0x9d, 0xff, 0x6f, 0xdd, 0xbe, 0x43, 0xb9, 0x7b, 0x6f, 0x47, 0x73, 0x49, 0x21, 0x93, 0x73, 0xf4, 0x74, 0x2b, 0x5d, 0x4c, 0xfd, 0xfe, 0x92, 0xbb, 0x57, 0xc5, 0xf7, 0x1f, 0x3c, 0x7c, 0xf4, 0x18, 0x8, 0x8f, 0x9f, 0x3c, 0x7d, 0xf6, 0xfc, 0xfe, 0xb, 0xed, 0x24, 0x66, 0x37, 0xe9, 0x75, 0x4b, 0xb5, 0x77, 0x60, 0xfb, 0xfa, 0x7, 0x54, 0xfc, 0xf2, 0xd5, 0x6b, 0x68, 0xe0, 0xcd, 0xdb, 0x97, 0x2f, 0x2c, 0xdf, 0x62, 0xb0, 0xbf, 0xaf, 0x7a, 0x9, 0xbe, 0xcd, 0x33, 0x84, 0xde, 0xbd, 0x7f, 0x2, 0x4d, 0x7c, 0x78, 0xff, 0xf1, 0x31, 0x58, 0x30, 0x34, 0xdc, 0x36, 0x42, 0x8f, 0xc0, 0x8, 0xae, 0x51, 0xf4, 0xe9, 0xf3, 0x17, 0x68, 0xe1, 0xeb, 0xb7, 0x34, 0x58, 0x31, 0xea, 0x12, 0xa8, 0x1, 0x2b, 0xba, 0xc7, 0x50, 0xe6, 0x19, 0xe8, 0xc8, 0x66, 0x80, 0x92, 0xcb, 0x17, 0x8a, 0x25, 0xd8, 0x2d, 0x94, 0xd1, 0x64, 0xf, 0x8, 0xe3, 0x13, 0x93, 0xf4, 0xe, 0x9c, 0xe4, 0x89, 0xe3, 0xfd, 0x3, 0xd0, 0x71, 0xb0, 0xf, 0x94, 0xc3, 0xa3, 0xdc, 0x71, 0x21, 0xb7, 0x4b, 0x2, 0x35, 0xa1, 0x4c, 0xd, 0x4b, 0x1c, 0x35, 0x90, 0xa7, 0x67, 0xf0, 0xc9, 0x29, 0xe8, 0x38, 0x3d, 0xa9, 0x1c, 0x80, 0x4, 0x1d, 0x9d, 0xed, 0x9e, 0x13, 0x3, 0x22, 0x94, 0xed, 0x59, 0x99, 0xa7, 0x6, 0x6d, 0x73, 0x2a, 0xbe, 0x6d, 0xf0, 0x60, 0x8f, 0x6f, 0x13, 0x25, 0x41, 0x65, 0xb9, 0xc8, 0xef, 0x1e, 0x1e, 0x1e, 0xee, 0x69, 0x2, 0x94, 0xf9, 0xb6, 0x8a, 0x81, 0xec, 0x55, 0x2d, 0x4f, 0xb0, 0x47, 0x4e, 0x90, 0xbf, 0xdc, 0x25, 0x91, 0x44, 0x74, 0x27, 0x90, 0x3c, 0xb, 0xc8, 0xf2, 0xd, 0xce, 0xcf, 0x60, 0xaf, 0x58, 0xaa, 0x18, 0xe8, 0xdf, 0x80, 0x15, 0x27, 0x6c, 0x7e, 0x61, 0xb7, 0x78, 0x5e, 0xcc, 0x43, 0xab, 0x1, 0xfd, 0x5, 0x9a, 0x7, 0x8b, 0x36, 0x79, 0xb0, 0x77, 0x76, 0x5, 0x90, 0x2b, 0xed, 0x55, 0x84, 0xb2, 0x18, 0x16, 0x98, 0x5a, 0x26, 0x2e, 0xe1, 0x5f, 0xce, 0x44, 0x5a, 0xb, 0x83, 0x3f, 0x5f, 0xb, 0xcb, 0xb4, 0x16, 0xcc, 0xab, 0xf1, 0x9a, 0xc6, 0xdb, 0x57, 0x23, 0xed, 0x7, 0x2b, 0xab, 0x2a, 0xba, 0x69, 0xed, 0x7, 0xe6, 0x6c, 0xaf, 0xae, 0xd5, 0xfa, 0x1, 0xed, 0x48, 0x8a, 0x7b, 0x7d, 0x3, 0xa5, 0x10, 0x6d, 0x48, 0xb8, 0x2, 0x2a, 0x2f, 0x30, 0xa2, 0x73, 0xdd, 0xad, 0x24, 0x9b, 0x7b, 0x5a, 0x97, 0x14, 0xf6, 0x44, 0x63, 0x53, 0xdb, 0x60, 0xcb, 0xf6, 0x54, 0x2c, 0xea, 0x9, 0x4b, 0x5d, 0x6c, 0x6b, 0x57, 0xee, 0x93, 0x5d, 0x13, 0xc3, 0xb3, 0x9b, 0x1, 0x1b, 0x36, 0x67, 0x87, 0x27, 0x5c, 0x72, 0x1f, 0xcf, 0xe8, 0xa7, 0xca, 0x88, 0x30, 0xb9, 0xd5, 0x66, 0x3f, 0x17, 0xda, 0xb6, 0x26, 0x85, 0x11, 0x96, 0x31, 0x99, 0x4c, 0xfc, 0xf, 0x40, 0x27, 0xd3, 0xbf, 0xc4, 0x77, 0x82, 0xde, 0x40, 0xde, 0x4b, 0x3f, 0xe2, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char toggle_on_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x74, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x12, 0x12, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x1a, 0x1a, 0x1e, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x2c, 0x36, 0x27, 0x49, 0x65, 0x29, 0x5d, 0x85, 0x2a, 0x66, 0x95, 0x2a, 0x68, 0x99, 0x29, 0x64, 0x92, 0x28, 0x4c, 0x6b, 0x25, 0x27, 0x2d, 0x27, 0x43, 0x5c, 0x29, 0x5f, 0x89, 0x27, 0x49, 0x66, 0x25, 0x30, 0x3e, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x25, 0x2d, 0x38, 0x25, 0x3a, 0x4c, 0x27, 0x4d, 0x6b, 0x29, 0x60, 0x8c, 0x27, 0x44, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x59, 0x7f, 0x25, 0x34, 0x43, 0x25, 0x35, 0x45, 0x28, 0x58, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x40, 0x57, 0x27, 0x41, 0x57, 0x25, 0x2a, 0x33, 0x29, 0x5d, 0x87, 0x25, 0x34, 0x44, 0x25, 0x2b, 0x34, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x27, 0x43, 0x5b, 0x27, 0x4d, 0x6c, 0x27, 0x4e, 0x6d, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x28, 0x56, 0x7b, 0x26, 0x3b, 0x4e, 0x26, 0x3a, 0x4e, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0xe4, 0xe4, 0xe5, 0x27, 0x44, 0x5d, 0xdd, 0xc9, 0xf2, 0x7e, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0x8, 0x17, 0x35, 0x73, 0xd9, 0x7, 0x3a, 0x96, 0xf9, 0x9a, 0xb, 0x28, 0x76, 0xfb, 0x77, 0xde, 0x45, 0x5, 0x82, 0xc6, 0xc6, 0x37, 0xf, 0xe9, 0x4c, 0x4e, 0x4f, 0x50, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x37, 0x21, 0x5a, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x65, 0xb5, 0xdd, 0x88, 0x9f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x2, 0x28, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x55, 0x69, 0x57, 0xd3, 0x40, 0x14, 0x25, 0x93, 0xa4, 0x49, 0x24, 0x49, 0xd9, 0x42, 0xd7, 0x0, 0x85, 0x50, 0x2c, 0xb4, 0x68, 0x5b, 0xab, 0x28, 0xb2, 0xc, 0x4b, 0x95, 0x82, 0x56, 0xab, 0x42, 0x45, 0x5c, 0x9b, 0xad, 0x45, 0x11, 0x6d, 0x3, 0xa8, 0x7f, 0xde, 0xc4, 0x94, 0x26, 0x69, 0x30, 0x89, 0xc7, 0x2f, 0x7a, 0x3f, 0xe4, 0x9c, 0xcc, 0x3b, 0xef, 0xce, 0x7d, 0x6f, 0xde, 0x32, 0x30, 0xf0, 0xf, 0x1, 0x1, 0x28, 0x8a, 0xf9, 0x2, 0x45, 0x1, 0x72, 0xa5, 0x3b, 0xc0, 0xf0, 0x10, 0x41, 0x52, 0xd7, 0x7c, 0x40, 0x91, 0x44, 0x8, 0xc7, 0x80, 0xfb, 0x76, 0x6c, 0x90, 0xa4, 0x19, 0x36, 0x3c, 0x34, 0x3c, 0xe2, 0x89, 0xe1, 0xa1, 0x30, 0xcb, 0xd0, 0xe4, 0x20, 0xd6, 0xa7, 0x2, 0x8c, 0x8e, 0x71, 0xe3, 0x91, 0x68, 0x2c, 0x9e, 0x80, 0x3e, 0x48, 0xc4, 0x63, 0xd1, 0xc8, 0x38, 0x37, 0x36, 0xea, 0x10, 0x1, 0x92, 0xfc, 0xc4, 0xe4, 0xd4, 0x86, 0x9f, 0xf3, 0x25, 0x36, 0xa6, 0x26, 0x27, 0xf8, 0xa4, 0x8d, 0x1, 0x49, 0x51, 0xd3, 0x33, 0x82, 0xa7, 0xcf, 0xe6, 0xd6, 0x76, 0xf9, 0x81, 0x89, 0x87, 0x3b, 0x9b, 0x50, 0x98, 0x99, 0xa6, 0x52, 0x88, 0x15, 0x3f, 0xc1, 0xcc, 0x7a, 0x6a, 0xaf, 0xec, 0xee, 0x3d, 0x7a, 0x5c, 0x7d, 0x62, 0xe0, 0x69, 0xed, 0xd9, 0xf3, 0x17, 0xfb, 0x95, 0xc4, 0x2c, 0x43, 0xf4, 0xf2, 0x0, 0xd2, 0x73, 0xd7, 0x33, 0x9e, 0xfe, 0x7, 0xf5, 0x97, 0xf6, 0xff, 0xc3, 0x57, 0x7, 0x95, 0xcc, 0xfc, 0x5c, 0xfa, 0x32, 0x8, 0x8c, 0x67, 0x17, 0xbc, 0xfc, 0x8f, 0x5e, 0xd7, 0x6b, 0xce, 0x93, 0x5a, 0xfd, 0xcd, 0xd1, 0x42, 0x96, 0xcf, 0x99, 0x12, 0x10, 0x9c, 0x5e, 0xf4, 0x8c, 0xff, 0xed, 0xbb, 0xf7, 0xfd, 0x47, 0x87, 0x7b, 0x1f, 0xe0, 0x22, 0x8d, 0x9b, 0x4, 0x20, 0xc4, 0xdc, 0xb0, 0x4c, 0xd, 0x51, 0x92, 0x15, 0xa8, 0x4a, 0x4d, 0xa8, 0xb6, 0xba, 0x47, 0xc7, 0x1f, 0xdd, 0xa4, 0x9f, 0x8e, 0xe1, 0xcd, 0x7c, 0xc1, 0x8c, 0x1, 0x25, 0xd8, 0x98, 0x65, 0x69, 0x9d, 0x34, 0x3e, 0x4b, 0xd, 0x55, 0x6a, 0x59, 0x4, 0xa7, 0x5f, 0xdc, 0x4, 0x5f, 0x4f, 0x61, 0x31, 0x4b, 0xa0, 0x26, 0x1, 0x79, 0x2b, 0x6e, 0x9, 0x90, 0xda, 0x10, 0x9e, 0x74, 0x54, 0x4d, 0x56, 0x7b, 0x4, 0x67, 0xe7, 0x6e, 0x82, 0xf3, 0x33, 0x28, 0x94, 0x48, 0xcc, 0x24, 0xe0, 0x6f, 0x5b, 0x6f, 0xa8, 0x6a, 0xfa, 0xe7, 0x42, 0x54, 0x5b, 0x17, 0x5a, 0x8f, 0xa0, 0x5c, 0x75, 0x13, 0x54, 0xcb, 0x10, 0xde, 0xe1, 0xbb, 0x4, 0x64, 0xd8, 0x2a, 0xa2, 0xb6, 0xa1, 0x40, 0xfc, 0xa6, 0x3b, 0x7f, 0x17, 0x3, 0x2b, 0x20, 0xd8, 0xa2, 0x65, 0xd1, 0x3a, 0xb0, 0x2d, 0x2b, 0x3a, 0x81, 0x22, 0x5, 0xcd, 0x1, 0x8, 0xe5, 0x6d, 0xaf, 0xa0, 0xca, 0x9a, 0x2c, 0xfe, 0x4a, 0xa0, 0x16, 0xf4, 0x15, 0xf4, 0x3a, 0x58, 0xb2, 0x99, 0xda, 0x9d, 0xa6, 0x9e, 0x4b, 0x5, 0xc2, 0xa6, 0xe2, 0x5d, 0x7, 0x4b, 0x5c, 0xb7, 0xe, 0xfe, 0xba, 0x12, 0x8d, 0x5e, 0x98, 0xff, 0xf3, 0x5e, 0xb8, 0x6b, 0xf5, 0x42, 0x80, 0x6e, 0xdc, 0x77, 0x76, 0xe3, 0xf, 0x67, 0x37, 0x1a, 0xf3, 0xe0, 0xde, 0xb2, 0xa7, 0x86, 0xfe, 0x79, 0x90, 0x59, 0xbe, 0x6f, 0x9b, 0x7, 0xc6, 0x44, 0xa2, 0x98, 0x95, 0x55, 0x18, 0x18, 0xab, 0x2b, 0xc, 0x95, 0x74, 0xce, 0xb4, 0x14, 0xc1, 0xb1, 0x91, 0x68, 0x51, 0xf0, 0x77, 0x16, 0x8a, 0xd1, 0x8, 0xcb, 0x11, 0xa9, 0xbe, 0xc1, 0x8c, 0x60, 0x69, 0x92, 0xce, 0x67, 0x4b, 0x6b, 0x23, 0x3e, 0x58, 0x2b, 0x65, 0xf3, 0x34, 0x99, 0xc6, 0x5c, 0xbb, 0x1, 0x1, 0x39, 0xbc, 0xb0, 0xce, 0xfb, 0xef, 0x5, 0x7e, 0xbd, 0x80, 0xe7, 0xae, 0xde, 0x2d, 0xfa, 0x66, 0xf2, 0x5f, 0x4c, 0xfa, 0x6a, 0xfa, 0xcd, 0x66, 0xfa, 0x7f, 0xf1, 0x13, 0xb7, 0x71, 0x36, 0xc6, 0x87, 0x41, 0xd4, 0x5, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x74, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x12, 0x12, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x1a, 0x1a, 0x1e, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x2c, 0x36, 0x27, 0x49, 0x65, 0x29, 0x5d, 0x85, 0x2a, 0x66, 0x95, 0x2a, 0x68, 0x99, 0x29, 0x64, 0x92, 0x28, 0x4c, 0x6b, 0x25, 0x27, 0x2d, 0x27, 0x43, 0x5c, 0x29, 0x5f, 0x89, 0x27, 0x49, 0x66, 0x25, 0x30, 0x3e, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x25, 0x2d, 0x38, 0x25, 0x3a, 0x4c, 0x27, 0x4d, 0x6b, 0x29, 0x60, 0x8c, 0x27, 0x44, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x59, 0x7f, 0x25, 0x34, 0x43, 0x25, 0x35, 0x45, 0x28, 0x58, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x40, 0x57, 0x27, 0x41, 0x57, 0x25, 0x2a, 0x33, 0x29, 0x5d, 0x87, 0x25, 0x34, 0x44, 0x25, 0x2b, 0x34, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x27, 0x43, 0x5b, 0x27, 0x4d, 0x6c, 0x27, 0x4e, 0x6d, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x28, 0x56, 0x7b, 0x26, 0x3b, 0x4e, 0x26, 0x3a, 0x4e, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0xe4, 0xe4, 0xe5, 0x27, 0x44, 0x5d, 0xdd, 0xc9, 0xf2, 0x7e, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0x8, 0x17, 0x35, 0x73, 0xd9, 0x7, 0x3a, 0x96, 0xf9, 0x9a, 0xb, 0x28, 0x76, 0xfb, 0x77, 0xde, 0x45, 0x5, 0x82, 0xc6, 0xc6, 0x37, 0xf, 0xe9, 0x4c, 0x4e, 0x4f, 0x50, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x37, 0x21, 0x5a, 0x6c, 0x0, 0x0, 0x2, 0x4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x63, 0x83, 0xdc, 0x60, 0x10, 0xc7, 0x1b, 0x3c, 0xc1, 0xda, 0x3e, 0xdb, 0x36, 0xe7, 0x6c, 0xdb, 0xa, 0xcf, 0xc6, 0x7e, 0xf8, 0x2a, 0x6d, 0xb8, 0xac, 0x7b, 0xbf, 0xf7, 0xf3, 0x1f, 0xcf, 0x7c, 0xf8, 0x97, 0xc0, 0x70, 0x82, 0x20, 0xb3, 0x42, 0x10, 0x38, 0x96, 0xd2, 0x1c, 0x27, 0x11, 0x45, 0x33, 0xac, 0x2d, 0xb, 0x2c, 0x43, 0x53, 0x88, 0xc4, 0xad, 0xde, 0x49, 0x3b, 0xe3, 0x70, 0xba, 0xdc, 0x1e, 0xaf, 0x2f, 0x23, 0x5e, 0x8f, 0xdb, 0xe5, 0x74, 0x30, 0x76, 0xd2, 0x14, 0x5, 0xee, 0xf, 0x4, 0x43, 0xe1, 0x48, 0x34, 0x16, 0x87, 0x2c, 0xc4, 0x63, 0xd1, 0x48, 0x38, 0x14, 0xc, 0xf8, 0x71, 0x83, 0x7d, 0xa2, 0xa0, 0xb0, 0xa8, 0x78, 0x4, 0x72, 0x64, 0xa4, 0xb8, 0xa8, 0xb0, 0x20, 0xa1, 0x53, 0xc0, 0x4a, 0xd8, 0xd2, 0xb2, 0x72, 0xc8, 0xc4, 0xe8, 0xd8, 0xf8, 0xc4, 0xa4, 0xc2, 0xd4, 0xf4, 0x28, 0x94, 0x97, 0x95, 0xb2, 0x25, 0x98, 0x96, 0x3f, 0xed, 0xac, 0xc8, 0x18, 0xfb, 0xcc, 0xec, 0xdc, 0xfc, 0xc2, 0xe2, 0xd2, 0x17, 0x96, 0x57, 0x56, 0xd7, 0xd6, 0x37, 0x66, 0xe2, 0x15, 0x4e, 0x5a, 0xad, 0x3, 0x5e, 0x59, 0x55, 0x5d, 0x93, 0xd1, 0x7e, 0x73, 0x6b, 0x1b, 0x74, 0xec, 0xec, 0x6e, 0xce, 0xd4, 0xd4, 0x56, 0x55, 0x7e, 0x4f, 0x82, 0x2c, 0x70, 0xd5, 0x41, 0x6, 0xf6, 0xf6, 0xb7, 0x56, 0xc0, 0xc0, 0xca, 0xd6, 0xc1, 0x5e, 0x5d, 0x7d, 0x41, 0x83, 0x12, 0x2, 0x86, 0x1c, 0x8d, 0x90, 0x89, 0xc3, 0xa3, 0x63, 0x30, 0xb1, 0x33, 0x77, 0x2, 0x8d, 0xe, 0xa4, 0x8, 0xe0, 0x94, 0xb3, 0x9, 0x54, 0x4e, 0xcf, 0x38, 0x5e, 0x0, 0x91, 0x93, 0x40, 0x94, 0x41, 0xe1, 0xfc, 0x2, 0x2c, 0x5c, 0x9e, 0x43, 0x73, 0x4b, 0xab, 0x92, 0x3, 0x41, 0xbb, 0xa2, 0xa0, 0x22, 0x5f, 0x9d, 0x5e, 0x73, 0xa7, 0x22, 0x27, 0x6b, 0x2, 0x37, 0xb7, 0x60, 0xe1, 0xee, 0x6, 0xda, 0xea, 0x69, 0x42, 0x11, 0x60, 0xda, 0x63, 0x5a, 0x0, 0xdc, 0x3d, 0xc0, 0xd5, 0x83, 0xf8, 0xc8, 0x8b, 0xaa, 0xc0, 0xd3, 0x33, 0x58, 0x78, 0x7e, 0x82, 0xf2, 0xe, 0x86, 0x54, 0x4, 0xa, 0x3a, 0xb5, 0x1e, 0x8a, 0x8f, 0x0, 0xf0, 0x72, 0x26, 0xca, 0x2f, 0x8f, 0xaa, 0xc0, 0xc4, 0x22, 0x58, 0x58, 0x9c, 0x0, 0xe8, 0x2a, 0xf8, 0x26, 0xc0, 0xb8, 0xb5, 0x21, 0xba, 0xff, 0x12, 0xc1, 0xd9, 0xeb, 0x67, 0xe3, 0xb7, 0xb3, 0x9c, 0x23, 0xa0, 0x5d, 0x6d, 0xa0, 0xf2, 0xf8, 0x0, 0xf7, 0xbc, 0xf0, 0x59, 0x40, 0xe0, 0x72, 0xad, 0x1, 0x4e, 0xb5, 0xe8, 0xba, 0x20, 0xf2, 0x8f, 0xfc, 0xd9, 0xd7, 0x2, 0x3e, 0xe6, 0xda, 0x5, 0xc, 0x39, 0xba, 0x41, 0xe3, 0xfe, 0x41, 0x2, 0x38, 0x15, 0x0, 0x24, 0x21, 0xf3, 0x1c, 0x74, 0x7, 0x11, 0xf6, 0xd3, 0x93, 0xa8, 0xee, 0x42, 0x6d, 0xfe, 0xbb, 0xd0, 0xa3, 0xed, 0x42, 0xe, 0xdb, 0xb8, 0x61, 0xdc, 0xc6, 0xa4, 0xba, 0x8d, 0xea, 0x3d, 0xe8, 0xed, 0xab, 0xc9, 0xe7, 0x1e, 0xd4, 0xf4, 0xf5, 0xab, 0xf7, 0x40, 0xb9, 0x48, 0xac, 0x73, 0x60, 0x10, 0x72, 0x66, 0x70, 0xc0, 0xc9, 0x26, 0x8c, 0x37, 0xad, 0x84, 0xe, 0xba, 0xc2, 0x91, 0xb6, 0x72, 0xc8, 0x4a, 0x79, 0x5b, 0x24, 0xec, 0xa, 0xd2, 0x25, 0xb8, 0xf9, 0x2a, 0x57, 0x32, 0x8e, 0x96, 0xfa, 0x8e, 0x21, 0x5f, 0x16, 0x86, 0x3a, 0xea, 0x5b, 0x1c, 0x4c, 0x25, 0x89, 0x59, 0xbf, 0x4a, 0x3, 0x6a, 0x1d, 0x2e, 0xc8, 0xfe, 0x17, 0xa, 0x86, 0x5b, 0x51, 0x3, 0x8e, 0xa5, 0xf9, 0x4c, 0x64, 0xe, 0x68, 0x9f, 0xe9, 0xbd, 0xf0, 0x9, 0xb7, 0x71, 0x36, 0xc6, 0x9b, 0x3d, 0x7f, 0x21, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tool_button_pressed_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x2, 0x1, 0x50, 0x4c, 0x54, 0x45, 0x29, 0x3a, 0x40, 0x2d, 0x3e, 0x44, 0x26, 0x34, 0x3b, 0x24, 0x34, 0x39, 0x23, 0x31, 0x38, 0x22, 0x31, 0x37, 0x22, 0x31, 0x37, 0x22, 0x30, 0x36, 0x22, 0x31, 0x36, 0x26, 0x34, 0x3c, 0x32, 0x44, 0x4c, 0x26, 0x34, 0x39, 0x23, 0x31, 0x36, 0x21, 0x2e, 0x34, 0x1f, 0x2c, 0x30, 0x1f, 0x2b, 0x2f, 0x1f, 0x2a, 0x2e, 0x1e, 0x2b, 0x2f, 0x1f, 0x2b, 0x2e, 0x36, 0x4b, 0x52, 0x25, 0x33, 0x38, 0x20, 0x2f, 0x32, 0x1c, 0x29, 0x2e, 0x1b, 0x26, 0x2a, 0x1a, 0x23, 0x26, 0x18, 0x22, 0x26, 0x19, 0x22, 0x26, 0x19, 0x23, 0x26, 0x19, 0x26, 0x29, 0x20, 0x2d, 0x32, 0x25, 0x31, 0x38, 0x3c, 0x51, 0x59, 0x23, 0x31, 0x37, 0x1f, 0x2b, 0x31, 0x1a, 0x25, 0x2b, 0x17, 0x20, 0x24, 0x15, 0x1c, 0x21, 0x14, 0x1b, 0x21, 0x14, 0x1c, 0x21, 0x13, 0x1b, 0x21, 0x15, 0x1d, 0x21, 0x1a, 0x25, 0x2a, 0x40, 0x57, 0x60, 0x23, 0x31, 0x36, 0x1f, 0x2b, 0x31, 0x1b, 0x25, 0x29, 0x16, 0x1e, 0x23, 0x14, 0x1b, 0x1d, 0x12, 0x19, 0x1d, 0x12, 0x1b, 0x1d, 0x14, 0x1a, 0x1d, 0x45, 0x5e, 0x67, 0x22, 0x32, 0x37, 0x20, 0x2d, 0x31, 0x1a, 0x26, 0x2a, 0x15, 0x1f, 0x25, 0x14, 0x1c, 0x1f, 0x12, 0x1b, 0x1f, 0x12, 0x1b, 0x20, 0x14, 0x1b, 0x1f, 0x15, 0x1e, 0x24, 0x1a, 0x25, 0x29, 0x4b, 0x64, 0x6d, 0x23, 0x32, 0x38, 0x20, 0x2e, 0x32, 0x1b, 0x27, 0x2b, 0x17, 0x22, 0x27, 0x16, 0x1e, 0x23, 0x14, 0x1e, 0x23, 0x16, 0x20, 0x24, 0x14, 0x1e, 0x22, 0x15, 0x1e, 0x22, 0x17, 0x21, 0x27, 0x1c, 0x27, 0x2c, 0x4f, 0x6a, 0x75, 0x21, 0x2f, 0x33, 0x1d, 0x29, 0x2d, 0x19, 0x23, 0x2a, 0x18, 0x22, 0x27, 0x16, 0x21, 0x27, 0x18, 0x23, 0x29, 0x17, 0x21, 0x26, 0x19, 0x23, 0x29, 0x1c, 0x28, 0x2d, 0x21, 0x2e, 0x33, 0x54, 0x70, 0x7c, 0x23, 0x33, 0x38, 0x22, 0x30, 0x34, 0x1e, 0x2a, 0x2f, 0x1a, 0x26, 0x2d, 0x1a, 0x25, 0x2b, 0x19, 0x25, 0x2b, 0x1a, 0x26, 0x2d, 0x1a, 0x26, 0x2c, 0x18, 0x25, 0x2a, 0x1a, 0x24, 0x2a, 0x1a, 0x25, 0x2c, 0x1d, 0x2a, 0x2f, 0x22, 0x2f, 0x34, 0x59, 0x77, 0x82, 0x23, 0x33, 0x39, 0x22, 0x30, 0x35, 0x1f, 0x2c, 0x31, 0x1c, 0x28, 0x30, 0x1c, 0x28, 0x2e, 0x1b, 0x29, 0x2f, 0x1c, 0x2a, 0x31, 0x1b, 0x28, 0x2f, 0x1c, 0x28, 0x2d, 0x1b, 0x27, 0x2f, 0x1f, 0x2b, 0x31, 0x5e, 0x7d, 0x8a, 0x24, 0x34, 0x39, 0x21, 0x2f, 0x37, 0x20, 0x2d, 0x34, 0x1d, 0x2b, 0x33, 0x1d, 0x2b, 0x32, 0x1d, 0x2d, 0x35, 0x1e, 0x2e, 0x36, 0x1f, 0x2e, 0x36, 0x1d, 0x2b, 0x34, 0x1d, 0x2b, 0x31, 0x1d, 0x2b, 0x32, 0x20, 0x2d, 0x32, 0x21, 0x2f, 0x36, 0x63, 0x83, 0x90, 0x25, 0x34, 0x39, 0x21, 0x31, 0x36, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x36, 0x20, 0x31, 0x39, 0x21, 0x33, 0x3b, 0x21, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1e, 0x2d, 0x33, 0x1f, 0x2d, 0x33, 0x21, 0x30, 0x36, 0x67, 0x8a, 0x97, 0x24, 0x33, 0x39, 0x20, 0x30, 0x36, 0x1f, 0x2f, 0x35, 0x21, 0x30, 0x37, 0x22, 0x32, 0x39, 0x21, 0x35, 0x3e, 0x24, 0x37, 0x41, 0x24, 0x36, 0x41, 0x21, 0x33, 0x3c, 0x21, 0x31, 0x38, 0x1e, 0x2f, 0x35, 0x1e, 0x2e, 0x35, 0x20, 0x2e, 0x35, 0x24, 0x31, 0x39, 0x6c, 0x90, 0x9e, 0x22, 0x30, 0x36, 0x1f, 0x2e, 0x36, 0x20, 0x30, 0x36, 0x20, 0x31, 0x39, 0x23, 0x34, 0x3d, 0x23, 0x37, 0x41, 0x26, 0x3c, 0x47, 0x26, 0x3b, 0x46, 0x22, 0x35, 0x3f, 0x22, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1f, 0x2d, 0x35, 0x21, 0x30, 0x36, 0x72, 0x96, 0xa5, 0x72, 0x96, 0xa5, 0xe8, 0x14, 0xaa, 0x3f, 0x0, 0x0, 0x0, 0xaa, 0x74, 0x52, 0x4e, 0x53, 0xc3, 0xc3, 0xe6, 0xd7, 0xcb, 0xc3, 0xbf, 0xbe, 0xbd, 0xe5, 0xc3, 0xd7, 0xc0, 0xac, 0xa0, 0x9a, 0x98, 0x98, 0x98, 0xc3, 0xcb, 0xac, 0x92, 0x82, 0x7b, 0x78, 0x78, 0x7b, 0x82, 0xac, 0xcb, 0xc3, 0xc3, 0xa0, 0x82, 0x6f, 0x67, 0x64, 0x63, 0x64, 0x67, 0x82, 0xc3, 0xbf, 0x9a, 0x7a, 0x67, 0x5e, 0x5b, 0x5a, 0x5e, 0xc3, 0xbd, 0x98, 0x78, 0x64, 0x5b, 0x57, 0x57, 0x5b, 0x64, 0x78, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x77, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0xbb, 0x96, 0x76, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x76, 0x96, 0xc3, 0xb5, 0x92, 0x75, 0x62, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x59, 0x62, 0x74, 0x92, 0xc3, 0xa9, 0x8b, 0x71, 0x61, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x61, 0x71, 0x8b, 0xa9, 0xc3, 0x95, 0x7e, 0x6b, 0x5e, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x5e, 0x6b, 0x7e, 0x95, 0xc3, 0x4f, 0x78, 0x99, 0x30, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa9, 0x27, 0xf, 0x6, 0x4, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xff, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x40, 0x7, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x1c, 0x1c, 0x6c, 0xac, 0x2c, 0xcc, 0x9c, 0x8c, 0xc, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x2, 0x82, 0x82, 0x42, 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0xc, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0x52, 0x92, 0xd2, 0x32, 0x62, 0xb2, 0x72, 0xc2, 0xc, 0xf2, 0xa, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0x6a, 0xea, 0x1a, 0xca, 0x9a, 0x8a, 0xa, 0xf2, 0xc, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x6, 0x86, 0x86, 0x6, 0x46, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0xc, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0x56, 0x96, 0xd6, 0x36, 0xb6, 0xa6, 0x26, 0xc6, 0xc, 0x76, 0xf6, 0xe, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0xe, 0x26, 0x76, 0xc, 0x5e, 0xf6, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x1, 0x1, 0xfe, 0x81, 0x41, 0xc1, 0x21, 0xf6, 0x5e, 0xc, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x9, 0x89, 0x49, 0x61, 0xa1, 0xc, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xa9, 0x29, 0xc9, 0xc, 0xf9, 0x5, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0x5, 0xf9, 0xc, 0xb5, 0x75, 0xf5, 0xd, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0x75, 0xb5, 0xc, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x13, 0x26, 0x4e, 0x9a, 0x3c, 0x65, 0xea, 0xb4, 0xe9, 0x33, 0x66, 0x76, 0x33, 0xcc, 0x9a, 0x3d, 0x67, 0xee, 0xbc, 0xf9, 0xb, 0x16, 0x2e, 0x5a, 0xbc, 0x64, 0xe9, 0xb2, 0xe5, 0x2b, 0x66, 0x31, 0xac, 0x44, 0x3, 0x0, 0xa4, 0xd7, 0x4d, 0x73, 0x12, 0x21, 0x19, 0xde, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x1, 0xfe, 0x50, 0x4c, 0x54, 0x45, 0x29, 0x3a, 0x40, 0x2d, 0x3e, 0x44, 0x26, 0x34, 0x3b, 0x24, 0x34, 0x39, 0x23, 0x31, 0x38, 0x22, 0x31, 0x37, 0x22, 0x31, 0x37, 0x22, 0x30, 0x36, 0x22, 0x31, 0x36, 0x26, 0x34, 0x3c, 0x32, 0x44, 0x4c, 0x26, 0x34, 0x39, 0x23, 0x31, 0x36, 0x21, 0x2e, 0x34, 0x1f, 0x2c, 0x30, 0x1f, 0x2b, 0x2f, 0x1f, 0x2a, 0x2e, 0x1e, 0x2b, 0x2f, 0x1f, 0x2b, 0x2e, 0x36, 0x4b, 0x52, 0x25, 0x33, 0x38, 0x20, 0x2f, 0x32, 0x1c, 0x29, 0x2e, 0x1b, 0x26, 0x2a, 0x1a, 0x23, 0x26, 0x18, 0x22, 0x26, 0x19, 0x22, 0x26, 0x19, 0x23, 0x26, 0x19, 0x26, 0x29, 0x20, 0x2d, 0x32, 0x25, 0x31, 0x38, 0x3c, 0x51, 0x59, 0x23, 0x31, 0x37, 0x1f, 0x2b, 0x31, 0x1a, 0x25, 0x2b, 0x17, 0x20, 0x24, 0x15, 0x1c, 0x21, 0x14, 0x1b, 0x21, 0x14, 0x1c, 0x21, 0x13, 0x1b, 0x21, 0x15, 0x1d, 0x21, 0x1a, 0x25, 0x2a, 0x40, 0x57, 0x60, 0x23, 0x31, 0x36, 0x1f, 0x2b, 0x31, 0x1b, 0x25, 0x29, 0x16, 0x1e, 0x23, 0x14, 0x1b, 0x1d, 0x12, 0x19, 0x1d, 0x12, 0x1b, 0x1d, 0x14, 0x1a, 0x1d, 0x45, 0x5e, 0x67, 0x22, 0x32, 0x37, 0x20, 0x2d, 0x31, 0x1a, 0x26, 0x2a, 0x15, 0x1f, 0x25, 0x14, 0x1c, 0x1f, 0x12, 0x1b, 0x1f, 0x12, 0x1b, 0x20, 0x14, 0x1b, 0x1f, 0x15, 0x1e, 0x24, 0x1a, 0x25, 0x29, 0x4b, 0x64, 0x6d, 0x23, 0x32, 0x38, 0x20, 0x2e, 0x32, 0x1b, 0x27, 0x2b, 0x17, 0x22, 0x27, 0x16, 0x1e, 0x23, 0x14, 0x1e, 0x23, 0x16, 0x20, 0x24, 0x14, 0x1e, 0x22, 0x15, 0x1e, 0x22, 0x17, 0x21, 0x27, 0x1c, 0x27, 0x2c, 0x4f, 0x6a, 0x75, 0x21, 0x2f, 0x33, 0x1d, 0x29, 0x2d, 0x19, 0x23, 0x2a, 0x18, 0x22, 0x27, 0x16, 0x21, 0x27, 0x18, 0x23, 0x29, 0x17, 0x21, 0x26, 0x19, 0x23, 0x29, 0x1c, 0x28, 0x2d, 0x21, 0x2e, 0x33, 0x54, 0x70, 0x7c, 0x23, 0x33, 0x38, 0x22, 0x30, 0x34, 0x1e, 0x2a, 0x2f, 0x1a, 0x26, 0x2d, 0x1a, 0x25, 0x2b, 0x19, 0x25, 0x2b, 0x1a, 0x26, 0x2d, 0x1a, 0x26, 0x2c, 0x18, 0x25, 0x2a, 0x1a, 0x24, 0x2a, 0x1a, 0x25, 0x2c, 0x1d, 0x2a, 0x2f, 0x22, 0x2f, 0x34, 0x59, 0x77, 0x82, 0x23, 0x33, 0x39, 0x22, 0x30, 0x35, 0x1f, 0x2c, 0x31, 0x1c, 0x28, 0x30, 0x1c, 0x28, 0x2e, 0x1b, 0x29, 0x2f, 0x1c, 0x2a, 0x31, 0x1b, 0x28, 0x2f, 0x1c, 0x28, 0x2d, 0x1b, 0x27, 0x2f, 0x1f, 0x2b, 0x31, 0x5e, 0x7d, 0x8a, 0x24, 0x34, 0x39, 0x21, 0x2f, 0x37, 0x20, 0x2d, 0x34, 0x1d, 0x2b, 0x33, 0x1d, 0x2b, 0x32, 0x1d, 0x2d, 0x35, 0x1e, 0x2e, 0x36, 0x1f, 0x2e, 0x36, 0x1d, 0x2b, 0x34, 0x1d, 0x2b, 0x31, 0x1d, 0x2b, 0x32, 0x20, 0x2d, 0x32, 0x21, 0x2f, 0x36, 0x63, 0x83, 0x90, 0x25, 0x34, 0x39, 0x21, 0x31, 0x36, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x36, 0x20, 0x31, 0x39, 0x21, 0x33, 0x3b, 0x21, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1e, 0x2d, 0x33, 0x1f, 0x2d, 0x33, 0x21, 0x30, 0x36, 0x67, 0x8a, 0x97, 0x24, 0x33, 0x39, 0x20, 0x30, 0x36, 0x1f, 0x2f, 0x35, 0x21, 0x30, 0x37, 0x22, 0x32, 0x39, 0x21, 0x35, 0x3e, 0x24, 0x37, 0x41, 0x24, 0x36, 0x41, 0x21, 0x33, 0x3c, 0x21, 0x31, 0x38, 0x1e, 0x2f, 0x35, 0x1e, 0x2e, 0x35, 0x20, 0x2e, 0x35, 0x24, 0x31, 0x39, 0x6c, 0x90, 0x9e, 0x22, 0x30, 0x36, 0x1f, 0x2e, 0x36, 0x20, 0x30, 0x36, 0x20, 0x31, 0x39, 0x23, 0x34, 0x3d, 0x23, 0x37, 0x41, 0x26, 0x3c, 0x47, 0x26, 0x3b, 0x46, 0x22, 0x35, 0x3f, 0x22, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1f, 0x2d, 0x35, 0x21, 0x30, 0x36, 0x72, 0x96, 0xa5, 0x7e, 0x8c, 0xc3, 0xb0, 0x0, 0x0, 0x0, 0xaa, 0x74, 0x52, 0x4e, 0x53, 0xc3, 0xc3, 0xe6, 0xd7, 0xcb, 0xc3, 0xbf, 0xbe, 0xbd, 0xe5, 0xc3, 0xd7, 0xc0, 0xac, 0xa0, 0x9a, 0x98, 0x98, 0x98, 0xc3, 0xcb, 0xac, 0x92, 0x82, 0x7b, 0x78, 0x78, 0x7b, 0x82, 0xac, 0xcb, 0xc3, 0xc3, 0xa0, 0x82, 0x6f, 0x67, 0x64, 0x63, 0x64, 0x67, 0x82, 0xc3, 0xbf, 0x9a, 0x7a, 0x67, 0x5e, 0x5b, 0x5a, 0x5e, 0xc3, 0xbd, 0x98, 0x78, 0x64, 0x5b, 0x57, 0x57, 0x5b, 0x64, 0x78, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x77, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0xbb, 0x96, 0x76, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x76, 0x96, 0xc3, 0xb5, 0x92, 0x75, 0x62, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x59, 0x62, 0x74, 0x92, 0xc3, 0xa9, 0x8b, 0x71, 0x61, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x61, 0x71, 0x8b, 0xa9, 0xc3, 0x95, 0x7e, 0x6b, 0x5e, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x5e, 0x6b, 0x7e, 0x95, 0xc3, 0x4f, 0x78, 0x99, 0x30, 0x0, 0x0, 0x0, 0x67, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5c, 0x8b, 0x5, 0x2, 0xc3, 0x30, 0xc, 0xc4, 0x72, 0x5d, 0x39, 0xf4, 0xff, 0x67, 0x8e, 0x79, 0x1a, 0x37, 0xa0, 0xa0, 0x6d, 0x5d, 0x6b, 0x2a, 0x5a, 0xfd, 0x30, 0xe6, 0x1, 0xf4, 0xa7, 0x76, 0xfa, 0x37, 0x74, 0x7, 0x98, 0x52, 0x83, 0x46, 0x97, 0x41, 0xfb, 0xd6, 0x2d, 0x86, 0xae, 0xfe, 0x84, 0x6b, 0x6d, 0x32, 0x6e, 0x58, 0x28, 0x22, 0x3a, 0x41, 0x32, 0xde, 0xd7, 0x6a, 0x67, 0x5b, 0xb7, 0xb7, 0xc9, 0xb0, 0xd8, 0xd6, 0x3a, 0x65, 0x34, 0xb4, 0x21, 0x8f, 0x1c, 0x3, 0x6d, 0x21, 0x84, 0x5d, 0x32, 0x8a, 0x48, 0x22, 0x6e, 0xda, 0xa8, 0x92, 0x36, 0x3e, 0x87, 0xea, 0x7b, 0x7e, 0x0, 0x62, 0xa8, 0x25, 0xad, 0x68, 0x1d, 0x7d, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tooltip_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0xdd, 0xdd, 0xdd, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0xdd, 0xdd, 0xdd, 0xfe, 0x3f, 0x83, 0xa9, 0x0, 0x0, 0x0, 0xd, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xcc, 0xff, 0xb7, 0x4a, 0xbe, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xc, 0x81, 0xb3, 0x51, 0x63, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x44, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xc5, 0xcf, 0xbb, 0x15, 0x0, 0x20, 0x8, 0x43, 0xd1, 0x80, 0x28, 0xf8, 0x41, 0xf7, 0xdf, 0xd6, 0x86, 0x63, 0xa1, 0x3, 0x78, 0xcb, 0x54, 0x79, 0x0, 0x71, 0x92, 0x90, 0x98, 0x0, 0xca, 0x45, 0x2d, 0x68, 0xc9, 0x4, 0xae, 0xad, 0x7b, 0xe8, 0xad, 0x32, 0x44, 0xe7, 0x1a, 0x61, 0x4d, 0x15, 0x88, 0xf9, 0x38, 0xdc, 0xfe, 0xd, 0xf7, 0xb1, 0xe7, 0xfa, 0x13, 0x77, 0xe7, 0x6f, 0xdc, 0x6c, 0x9, 0x25, 0x82, 0x67, 0x68, 0x78, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0xdd, 0xdd, 0xdd, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0xbc, 0x3, 0x4f, 0xe9, 0x0, 0x0, 0x0, 0xd, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xcc, 0xff, 0xb7, 0x4a, 0xbe, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x54, 0x76, 0x1, 0x2, 0x23, 0x1, 0x6, 0xd1, 0xf4, 0xe, 0x20, 0x28, 0xb, 0x64, 0xd0, 0x5c, 0x7d, 0x17, 0x8, 0x76, 0x4d, 0x62, 0x70, 0x7f, 0x7f, 0x6, 0x8, 0xfe, 0x95, 0x30, 0x78, 0xdc, 0x1, 0x31, 0xce, 0xb6, 0x50, 0xc8, 0x80, 0x1b, 0x8, 0xb7, 0x2, 0x6e, 0x29, 0xdc, 0x19, 0x0, 0xcf, 0x24, 0x4d, 0xb3, 0xd0, 0x4d, 0xb9, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xd, 0xf6, 0xb4, 0x61, 0xf5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_bg_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x95, 0xce, 0x31, 0x12, 0x2, 0x21, 0x10, 0x44, 0xd1, 0x3f, 0x40, 0xa1, 0x44, 0xa6, 0x46, 0xde, 0x63, 0x4f, 0xe5, 0x15, 0x38, 0xb2, 0xd6, 0x6, 0xb0, 0xc8, 0x30, 0x6, 0x96, 0xac, 0x56, 0x99, 0xf8, 0xb3, 0x7e, 0x51, 0xcb, 0xf9, 0x1a, 0xb3, 0x3f, 0xa, 0xaf, 0xc, 0xad, 0x2d, 0xcb, 0xe5, 0x76, 0x38, 0x5, 0x76, 0xec, 0x6c, 0xf7, 0xe0, 0x53, 0xe0, 0x13, 0xa1, 0x27, 0x27, 0x43, 0x26, 0x81, 0x20, 0xc8, 0x70, 0xfc, 0xe8, 0xf, 0x34, 0x67, 0xd8, 0x9c, 0x86, 0x61, 0x2e, 0x68, 0xe9, 0x91, 0xaf, 0x4b, 0x5a, 0x7d, 0x2a, 0x2c, 0x3, 0xed, 0xef, 0x1e, 0x6b, 0xcb, 0x4f, 0xa6, 0x66, 0x2b, 0x25, 0x6, 0x1, 0x37, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x94, 0xc8, 0x67, 0x6b, 0x60, 0xe6, 0x60, 0x64, 0x80, 0x80, 0xff, 0xc, 0x7f, 0x7f, 0xfc, 0x6a, 0x60, 0x94, 0xfb, 0xc0, 0xce, 0xcf, 0xc2, 0x80, 0x10, 0xfc, 0xc3, 0xf0, 0xf3, 0x23, 0xa3, 0xe2, 0x4f, 0xe, 0x36, 0x54, 0xc1, 0x1f, 0xbf, 0x18, 0x95, 0xbe, 0x73, 0x70, 0xb0, 0x30, 0xc0, 0x1, 0x48, 0xf0, 0x7, 0x85, 0x82, 0x58, 0x2d, 0xc2, 0xe6, 0xa4, 0x4f, 0x20, 0xc7, 0x37, 0x32, 0xb3, 0x23, 0x39, 0xfe, 0xfb, 0xaf, 0x46, 0x0, 0xee, 0x2a, 0x2f, 0xce, 0x4c, 0x47, 0x66, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_bg_focus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x73, 0x7a, 0x7a, 0xf4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0xb, 0x4, 0x12, 0x2d, 0x3a, 0xb5, 0x1b, 0x14, 0x49, 0x0, 0x0, 0x2, 0xd9, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xc5, 0x57, 0x31, 0x8e, 0x14, 0x31, 0x10, 0xac, 0xea, 0x3d, 0x11, 0x91, 0xdf, 0x49, 0xf7, 0xf, 0x78, 0x1, 0xf, 0x40, 0x84, 0x44, 0x10, 0xf2, 0x20, 0x42, 0x62, 0x12, 0xc4, 0x3, 0x78, 0x1, 0xff, 0x21, 0x42, 0xb8, 0x8a, 0xc0, 0x1e, 0x4f, 0xdb, 0xe3, 0xb9, 0xbb, 0x45, 0x20, 0x7c, 0x1a, 0xdd, 0x8c, 0xec, 0xed, 0xae, 0xae, 0xea, 0xee, 0xe9, 0xe1, 0xfd, 0xed, 0xdd, 0xb, 0x0, 0xdf, 0xf1, 0x7f, 0xd6, 0x4b, 0xde, 0xdf, 0xde, 0xf9, 0xcb, 0xeb, 0x9f, 0xff, 0xc5, 0xfb, 0x9b, 0xaf, 0xcf, 0x70, 0xb3, 0x3d, 0x3c, 0xff, 0xf0, 0xd, 0x24, 0x11, 0x71, 0x1, 0x49, 0x90, 0x4, 0x0, 0x4, 0xd3, 0x2f, 0xb6, 0x7b, 0xf, 0xff, 0x86, 0x2d, 0x8c, 0x47, 0x60, 0x1b, 0x0, 0x61, 0x1b, 0xb6, 0x21, 0x15, 0xd8, 0xc6, 0x8f, 0x8f, 0xaf, 0x0, 0x60, 0x7, 0x0, 0xa2, 0x2, 0x20, 0x11, 0x41, 0x30, 0xa2, 0x2, 0xc1, 0xb5, 0x0, 0x8c, 0x79, 0xd9, 0x80, 0x24, 0x48, 0x0, 0x48, 0x28, 0x9d, 0xb9, 0xd9, 0xd, 0xb0, 0x31, 0x40, 0x5c, 0x2e, 0x1, 0x46, 0x0, 0xd, 0xd0, 0xb6, 0xef, 0x35, 0x8e, 0x13, 0x6, 0xbc, 0x33, 0x60, 0xa3, 0x9a, 0x11, 0x6c, 0x82, 0xe6, 0xa, 0x0, 0x86, 0xe8, 0x2f, 0x71, 0xa9, 0xf7, 0x9c, 0x4d, 0x1f, 0x69, 0x5e, 0x1, 0xd8, 0xa3, 0x37, 0xa4, 0xa, 0x27, 0x1a, 0x13, 0x79, 0x25, 0x9, 0xaa, 0xe3, 0xd8, 0x9c, 0x5f, 0xea, 0x7d, 0x67, 0x80, 0xd7, 0x31, 0x20, 0xab, 0x3, 0x20, 0x5, 0x20, 0x2a, 0x13, 0x41, 0x40, 0x2b, 0x0, 0x76, 0x22, 0xb9, 0xb1, 0xd1, 0x92, 0x91, 0x5d, 0x86, 0xf3, 0x35, 0xef, 0x5, 0xa3, 0x25, 0x60, 0xd, 0x6e, 0x66, 0xe5, 0x0, 0xc0, 0xa8, 0x54, 0x1, 0x6, 0xe9, 0x16, 0x9f, 0x4f, 0xdc, 0x1c, 0x13, 0xed, 0xb1, 0x55, 0x31, 0x78, 0x70, 0x8e, 0xca, 0xcb, 0x8e, 0x6a, 0xbe, 0x56, 0x88, 0x67, 0x38, 0xdb, 0x75, 0x58, 0x76, 0xdf, 0x1b, 0x6c, 0x7a, 0xc, 0x6c, 0x90, 0x0, 0xfd, 0xe0, 0xe8, 0x98, 0xe4, 0x4, 0xe2, 0x69, 0xc, 0xe4, 0x40, 0xaa, 0xf9, 0x63, 0x70, 0xbb, 0x4, 0x16, 0x9c, 0x12, 0xa7, 0x3e, 0xe7, 0x38, 0xb3, 0x4, 0x2b, 0x6f, 0xc7, 0x23, 0xbb, 0xc3, 0x66, 0xdb, 0x38, 0x7, 0x0, 0xcf, 0x32, 0x34, 0xb6, 0x52, 0xb4, 0x3c, 0xf7, 0x35, 0x10, 0xd9, 0xf7, 0x6, 0x56, 0x93, 0x4, 0x4b, 0x0, 0x43, 0x28, 0xf9, 0x4a, 0x3d, 0x6e, 0xb0, 0x3e, 0x9, 0x31, 0xa9, 0x62, 0xd6, 0xc4, 0x36, 0x9c, 0xf2, 0xd9, 0xbd, 0x41, 0x2d, 0x24, 0x68, 0xc7, 0x1f, 0x62, 0x60, 0x6a, 0xc1, 0x7f, 0x95, 0x81, 0xaa, 0x13, 0x61, 0x9, 0xa6, 0xf6, 0x1c, 0x30, 0x17, 0x11, 0x6f, 0x48, 0x12, 0x3b, 0xf3, 0x7b, 0xc2, 0xeb, 0xca, 0x92, 0xb7, 0x72, 0x5f, 0x31, 0x90, 0x11, 0x4e, 0x48, 0xb3, 0x13, 0xa6, 0xcc, 0x3e, 0x51, 0x60, 0x91, 0x53, 0x55, 0x87, 0xf3, 0x2a, 0x98, 0xff, 0x7c, 0x6c, 0x1a, 0xf9, 0xec, 0xda, 0xeb, 0x94, 0x13, 0x43, 0xdd, 0x3f, 0x2a, 0x41, 0xd2, 0xb, 0x27, 0x65, 0xe8, 0x13, 0x20, 0x29, 0x3f, 0xc6, 0x7c, 0x48, 0x65, 0x8, 0x41, 0xda, 0xa4, 0xd5, 0x11, 0xc0, 0x2a, 0x61, 0xce, 0x18, 0x58, 0xd2, 0xbe, 0x98, 0x48, 0x96, 0xdd, 0xf5, 0xbc, 0x11, 0x65, 0xb6, 0x12, 0x55, 0xcb, 0xde, 0xb3, 0x78, 0x27, 0x78, 0xdc, 0xcb, 0x72, 0xe6, 0xd7, 0x8a, 0x27, 0xe6, 0x52, 0x1f, 0x10, 0xe0, 0xb8, 0x92, 0x81, 0xb4, 0x3f, 0x1, 0x1d, 0xed, 0x6c, 0xd4, 0xef, 0x12, 0x2f, 0x73, 0xa0, 0xe, 0xf, 0x42, 0x24, 0x20, 0xf, 0x91, 0xbf, 0x6e, 0x44, 0xfb, 0xde, 0xa1, 0x4, 0xa5, 0x7, 0xaa, 0xa0, 0x23, 0xad, 0xd4, 0x4b, 0xaa, 0x73, 0x0, 0xb7, 0xa1, 0x82, 0x87, 0x46, 0x74, 0x9a, 0xf, 0x48, 0x5d, 0xb3, 0xd, 0xa2, 0xb0, 0x96, 0xe5, 0x7d, 0xc8, 0x81, 0x19, 0xf1, 0x36, 0x2b, 0xba, 0xbd, 0x5e, 0xb3, 0xb7, 0x55, 0x12, 0x76, 0x90, 0xc4, 0x3a, 0x1, 0xa7, 0x66, 0xbc, 0x3, 0x90, 0xe0, 0x8, 0xc8, 0x42, 0x29, 0xa5, 0x7b, 0xa2, 0x63, 0x9f, 0x88, 0x26, 0xa, 0x9c, 0x85, 0x6f, 0x7b, 0x2b, 0x0, 0x92, 0x51, 0x4a, 0x81, 0x5c, 0x2a, 0xcb, 0x2a, 0x47, 0x0, 0xb0, 0x2b, 0x8, 0x11, 0x62, 0x20, 0x58, 0x20, 0x47, 0x77, 0x5a, 0xe5, 0x98, 0x43, 0x3f, 0x2, 0xd8, 0xc1, 0xa5, 0x39, 0x40, 0x82, 0xb5, 0xd9, 0xd7, 0x5a, 0x2, 0x59, 0x80, 0x9, 0x8a, 0x0, 0x7f, 0x1, 0x8, 0x44, 0x8, 0x64, 0xe0, 0xe8, 0x6e, 0x4b, 0xb4, 0x87, 0xa6, 0xc4, 0x3d, 0x17, 0x24, 0xa3, 0xa8, 0xc0, 0x32, 0x8a, 0xea, 0x33, 0x67, 0x0, 0x6e, 0xc, 0x94, 0x5e, 0xe2, 0x46, 0x11, 0x3a, 0x0, 0x82, 0x57, 0x1, 0x98, 0xbf, 0xb, 0xa4, 0xf6, 0x55, 0xd4, 0x2a, 0xe1, 0x0, 0x40, 0xf5, 0xf3, 0xa5, 0xd3, 0x16, 0x6a, 0xb4, 0xa7, 0x19, 0xfa, 0x4f, 0x18, 0xe8, 0x2c, 0x34, 0xfb, 0x92, 0x20, 0xbb, 0xf, 0xa3, 0x1d, 0xc0, 0xcd, 0xe7, 0xb7, 0x83, 0xf9, 0xf2, 0x24, 0xd3, 0xd7, 0xaf, 0x40, 0x9a, 0x84, 0x1, 0xf0, 0xfe, 0xf6, 0xee, 0x1d, 0x80, 0x4f, 0xff, 0xc8, 0xdf, 0x63, 0xeb, 0xfd, 0x6f, 0x3, 0x74, 0x35, 0xa7, 0x2a, 0xf0, 0x17, 0xed, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x73, 0x7a, 0x7a, 0xf4, 0x0, 0x0, 0x2, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x91, 0x16, 0x97, 0x30, 0x63, 0x60, 0x60, 0x38, 0xc9, 0x30, 0x30, 0xc0, 0x9c, 0x11, 0xe8, 0x80, 0xff, 0x6b, 0x3, 0x7f, 0xd, 0x88, 0xed, 0xc1, 0xeb, 0xd9, 0x18, 0x58, 0x60, 0x1c, 0x9e, 0xac, 0xdd, 0x0, 0x5a, 0xcb, 0x6, 0xc5, 0x99, 0x23, 0x6, 0xa2, 0xaf, 0xe4, 0xb3, 0xe5, 0x8a, 0x39, 0x69, 0xf8, 0xcf, 0xa8, 0x82, 0x2d, 0x52, 0xe0, 0x1e, 0x61, 0x63, 0xe0, 0x93, 0x29, 0x7a, 0x66, 0xdb, 0xdb, 0x7a, 0x5d, 0x92, 0x96, 0x45, 0x12, 0x55, 0xf, 0x24, 0xbd, 0x4, 0x50, 0x22, 0x81, 0x98, 0x70, 0x96, 0x63, 0x2b, 0x91, 0x3d, 0xdb, 0x80, 0xb0, 0xfd, 0x52, 0xf7, 0x85, 0x6d, 0xfe, 0xf9, 0xfb, 0x2f, 0x0, 0x2, 0x80, 0x18, 0x80, 0xa7, 0x4a, 0xa8, 0x6a, 0x40, 0xf8, 0x15, 0xc0, 0x9c, 0x61, 0x43, 0x77, 0xd3, 0xd, 0x48, 0x34, 0xce, 0x5e, 0x0, 0x84, 0xd0, 0x24, 0xe7, 0xf1, 0xa8, 0x17, 0x0, 0x3, 0x94, 0x7d, 0xef, 0x1c, 0xec, 0xe, 0x98, 0x38, 0x60, 0x33, 0xc7, 0x34, 0xb6, 0x90, 0xb5, 0x1, 0xf0, 0x76, 0xfb, 0x47, 0x3d, 0xe6, 0x59, 0x62, 0x89, 0x5, 0x60, 0x8f, 0xb1, 0x7d, 0x70, 0x6a, 0x9c, 0x20, 0xf1, 0x5e, 0x82, 0x49, 0x5c, 0xff, 0x27, 0x7f, 0xcc, 0x73, 0x1c, 0xd0, 0x6f, 0xe, 0xb4, 0x3b, 0x0, 0x52, 0x3, 0x35, 0x4e, 0x94, 0xa0, 0x37, 0x0, 0x9b, 0xa4, 0x18, 0x37, 0x5e, 0xd2, 0xe8, 0xd3, 0x2d, 0xd7, 0xbd, 0x52, 0x61, 0x3b, 0x97, 0x3b, 0x5c, 0xb9, 0x3, 0x98, 0xb1, 0xa, 0x8c, 0x34, 0xeb, 0x68, 0xef, 0xc2, 0x9f, 0x22, 0xc, 0x4e, 0xf2, 0x80, 0x42, 0xa8, 0x4e, 0xdd, 0x89, 0x8f, 0x50, 0xb4, 0x84, 0x9d, 0xbd, 0xb7, 0x33, 0x6d, 0xc0, 0x7b, 0x9, 0xc8, 0x17, 0xdf, 0x13, 0x4b, 0xca, 0xf3, 0x2f, 0xe, 0x24, 0x69, 0x8e, 0xf7, 0x68, 0x2d, 0x81, 0xfb, 0xa9, 0xfc, 0xe2, 0xbc, 0x73, 0xdc, 0x51, 0x7c, 0x1d, 0x9, 0xdd, 0x1, 0x72, 0xb6, 0x59, 0x1, 0x26, 0xe, 0xc2, 0xb8, 0x85, 0xf7, 0xe, 0xd8, 0x71, 0xe2, 0x9e, 0x6e, 0xae, 0x8e, 0x18, 0x2d, 0x0, 0x9, 0x1f, 0xd2, 0xbd, 0x17, 0xb4, 0x14, 0xc2, 0xc7, 0x29, 0x2, 0x33, 0x9f, 0x1c, 0xc5, 0xbc, 0x3, 0x5b, 0x9, 0x8c, 0xf9, 0xe2, 0x80, 0xff, 0xa0, 0x3, 0x53, 0x27, 0xe1, 0x6e, 0xac, 0x26, 0x3d, 0x60, 0x2d, 0x37, 0x36, 0xb9, 0x26, 0xc7, 0xa3, 0xd9, 0x9a, 0x2e, 0xea, 0xa7, 0x7a, 0x3, 0x38, 0x8, 0x23, 0xb8, 0x25, 0x51, 0x3a, 0xfb, 0xc3, 0x5c, 0x2c, 0x0, 0xf0, 0x69, 0xa, 0xce, 0x8f, 0x47, 0x5b, 0x18, 0x7f, 0x9f, 0x46, 0x3, 0x6f, 0x73, 0xff, 0xb5, 0x4, 0x26, 0xf5, 0x62, 0x1f, 0x43, 0xbc, 0x81, 0xa4, 0x3f, 0x12, 0xeb, 0x18, 0xd2, 0x74, 0x37, 0xf6, 0xe8, 0xcb, 0x1f, 0xa2, 0x88, 0x3d, 0x16, 0x1e, 0xed, 0x25, 0x38, 0xc5, 0x5e, 0x82, 0xd3, 0x2d, 0x13, 0x89, 0x25, 0x74, 0x47, 0xf0, 0xfb, 0x9e, 0xf1, 0x32, 0x86, 0x29, 0xc6, 0xe2, 0x0, 0xd, 0xae, 0x1f, 0x1d, 0x30, 0x9, 0x2d, 0xf6, 0x47, 0xcd, 0xc8, 0x23, 0x3e, 0x4c, 0x41, 0x77, 0x53, 0xae, 0x2f, 0x0, 0xbe, 0x97, 0xc0, 0xb7, 0xbd, 0xfb, 0x8, 0x76, 0x20, 0x56, 0x80, 0x50, 0x32, 0x5f, 0x46, 0x12, 0x68, 0xf6, 0x24, 0xa1, 0xb5, 0xf9, 0xd7, 0x9f, 0x25, 0xc9, 0x9c, 0x75, 0x81, 0x1b, 0x3e, 0x4f, 0xc1, 0xe8, 0x24, 0x16, 0x42, 0xd2, 0x40, 0x1c, 0xd9, 0xb6, 0x26, 0xc, 0xa4, 0x58, 0x1b, 0x70, 0x3e, 0x2c, 0x0, 0xdd, 0xb8, 0x8a, 0x76, 0x73, 0x5d, 0x57, 0x32, 0xc9, 0x45, 0xfe, 0x23, 0x3a, 0x2c, 0x8, 0x52, 0x32, 0xef, 0x0, 0xdd, 0x7e, 0x9d, 0xd9, 0xbe, 0xc6, 0xe5, 0xbe, 0xd6, 0x31, 0x1c, 0x88, 0x16, 0xad, 0xa2, 0x74, 0xd1, 0xae, 0x24, 0x95, 0xc4, 0xad, 0x6, 0xb, 0x0, 0x59, 0x1c, 0x67, 0xe7, 0x5c, 0x33, 0x6b, 0xef, 0x25, 0x68, 0x37, 0x58, 0xa8, 0x5, 0xfa, 0x17, 0x28, 0xaa, 0x1a, 0xa9, 0x96, 0x46, 0x77, 0x1c, 0xf8, 0x16, 0x71, 0xa0, 0x2f, 0xfc, 0x5a, 0xe7, 0x5d, 0x6b, 0x13, 0x76, 0x73, 0x89, 0x38, 0x72, 0x35, 0x1, 0x10, 0xfa, 0x9, 0x20, 0xe, 0xa4, 0xa9, 0x9f, 0xba, 0xc6, 0x5, 0x2f, 0x0, 0x6d, 0x43, 0x77, 0x6c, 0xab, 0x66, 0x6c, 0xa7, 0x7f, 0x73, 0x60, 0x77, 0x21, 0xe7, 0xf7, 0x53, 0x36, 0x75, 0x2, 0xfc, 0x37, 0x96, 0x15, 0xd1, 0x28, 0xc6, 0xff, 0x65, 0xa0, 0xd, 0x60, 0x2, 0x63, 0x4, 0x0, 0xf5, 0x8e, 0x13, 0x81, 0xf4, 0x3c, 0x86, 0x81, 0x1, 0x49, 0x0, 0x33, 0xd4, 0x35, 0xaa, 0x8d, 0x7e, 0xfe, 0xa5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_cursor_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc6, 0x50, 0x4c, 0x54, 0x45, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9c, 0xd4, 0xac, 0x9e, 0xd5, 0xaf, 0xa3, 0xd5, 0xb0, 0xa3, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xb0, 0xa3, 0xd6, 0xad, 0xa0, 0xd6, 0xad, 0xa0, 0xd5, 0xb0, 0xa3, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa5, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xdb, 0xb7, 0xad, 0xda, 0xb8, 0xae, 0xdb, 0xb9, 0xad, 0xdb, 0xb9, 0xad, 0xdb, 0xb7, 0xad, 0xdd, 0xba, 0xb1, 0xdd, 0xbb, 0xb1, 0xdd, 0xbd, 0xb1, 0xdd, 0xbf, 0xb3, 0xdd, 0xbd, 0xb3, 0xdf, 0xc1, 0xb7, 0xdf, 0xc0, 0xb5, 0xdf, 0xbf, 0xb5, 0xe1, 0xc3, 0xb9, 0xe1, 0xc3, 0xbb, 0xe1, 0xc5, 0xbb, 0xe2, 0xc7, 0xbe, 0xe1, 0xc5, 0xbd, 0xe4, 0xcb, 0xc2, 0xe3, 0xca, 0xc1, 0xe3, 0xcb, 0xc3, 0xe6, 0xce, 0xc6, 0xe6, 0xd0, 0xc6, 0xe8, 0xd1, 0xca, 0xe8, 0xd1, 0xca, 0xe8, 0xd0, 0xca, 0xe8, 0xcf, 0xca, 0xb7, 0x7d, 0x69, 0xb1, 0x77, 0x63, 0xac, 0x73, 0x5c, 0xa6, 0x69, 0x56, 0x9c, 0x67, 0x54, 0x93, 0x62, 0x51, 0x88, 0x60, 0x50, 0x0, 0x0, 0x0, 0x39, 0x76, 0x1d, 0xc2, 0x0, 0x0, 0x0, 0x3a, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x33, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x2f, 0x2f, 0xb8, 0xf, 0x95, 0x41, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x41, 0x89, 0xde, 0x6c, 0x4e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x9e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0xcf, 0x5b, 0x17, 0x81, 0x40, 0x14, 0x5, 0xe0, 0xe3, 0x9a, 0x4b, 0x2e, 0x31, 0x14, 0x62, 0x22, 0x53, 0x4d, 0x83, 0x44, 0xc, 0xa6, 0xa9, 0xf9, 0xff, 0xbf, 0xca, 0xd4, 0x5a, 0x1e, 0x7c, 0xfb, 0xec, 0xb5, 0x9f, 0xf, 0x7c, 0xfe, 0x80, 0x80, 0x86, 0xd6, 0x6c, 0x69, 0xed, 0x8e, 0x80, 0xbc, 0x6b, 0x18, 0xbd, 0xfe, 0x60, 0x68, 0x9a, 0xa3, 0xf1, 0x24, 0x7, 0x39, 0xb5, 0x2c, 0x6b, 0x36, 0x47, 0x68, 0x81, 0xd0, 0x52, 0x42, 0x61, 0x3b, 0xb6, 0xb3, 0x72, 0xd6, 0x1b, 0x77, 0xeb, 0xee, 0xa, 0x28, 0x31, 0xc6, 0x9e, 0x87, 0x3d, 0xbc, 0x3f, 0xf8, 0x7e, 0x9, 0xea, 0x48, 0x8, 0x9, 0xc2, 0x28, 0x22, 0x21, 0x9, 0x14, 0x28, 0x1a, 0x33, 0x16, 0xd3, 0x98, 0xb2, 0x98, 0x51, 0x5, 0xe5, 0x49, 0x3b, 0xeb, 0x5e, 0x74, 0x4a, 0x28, 0x92, 0xca, 0xb5, 0xbe, 0xa4, 0x0, 0x99, 0xde, 0xd2, 0xca, 0xbd, 0x5a, 0x9, 0x79, 0x96, 0x3d, 0xb2, 0x9f, 0x1c, 0xc4, 0x93, 0xf3, 0x17, 0xaf, 0xfb, 0xe6, 0x2, 0xfe, 0x5f, 0xf8, 0x2, 0x30, 0xbc, 0x1f, 0xb4, 0x2b, 0xfc, 0x80, 0xca, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9c, 0xd4, 0xac, 0x9e, 0xd5, 0xaf, 0xa3, 0xd5, 0xb0, 0xa3, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xb0, 0xa3, 0xd6, 0xad, 0xa0, 0xd6, 0xad, 0xa0, 0xd5, 0xb0, 0xa3, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa5, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xdb, 0xb7, 0xad, 0xda, 0xb8, 0xae, 0xdb, 0xb9, 0xad, 0xdb, 0xb9, 0xad, 0xdb, 0xb7, 0xad, 0xdd, 0xba, 0xb1, 0xdd, 0xbb, 0xb1, 0xdd, 0xbd, 0xb1, 0xdd, 0xbf, 0xb3, 0xdd, 0xbd, 0xb3, 0xdf, 0xc1, 0xb7, 0xdf, 0xc0, 0xb5, 0xdf, 0xbf, 0xb5, 0xe1, 0xc3, 0xb9, 0xe1, 0xc3, 0xbb, 0xe1, 0xc5, 0xbb, 0xe2, 0xc7, 0xbe, 0xe1, 0xc5, 0xbd, 0xe4, 0xcb, 0xc2, 0xe3, 0xca, 0xc1, 0xe3, 0xcb, 0xc3, 0xe6, 0xce, 0xc6, 0xe6, 0xd0, 0xc6, 0xe8, 0xd1, 0xca, 0xe8, 0xd1, 0xca, 0xe8, 0xd0, 0xca, 0xe8, 0xcf, 0xca, 0xb7, 0x7d, 0x69, 0xb1, 0x77, 0x63, 0xac, 0x73, 0x5c, 0xa6, 0x69, 0x56, 0x9c, 0x67, 0x54, 0x93, 0x62, 0x51, 0x88, 0x60, 0x50, 0x9e, 0xe4, 0xa3, 0x87, 0x0, 0x0, 0x0, 0x3a, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x33, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x2f, 0x2f, 0xb8, 0xf, 0x95, 0x41, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x4d, 0xc9, 0x1, 0xa, 0x2, 0x31, 0xc, 0x44, 0xd1, 0xff, 0xdb, 0xec, 0x2a, 0x1e, 0x48, 0xc0, 0xfb, 0x7b, 0x2c, 0x3b, 0x96, 0x2c, 0x88, 0x3, 0x19, 0x78, 0x19, 0x5f, 0xfc, 0xa7, 0x7c, 0xb, 0x78, 0xd5, 0xb3, 0x3c, 0x45, 0xf5, 0xea, 0xf2, 0x21, 0xb4, 0xc2, 0xd8, 0xbc, 0x19, 0xcd, 0xb0, 0xab, 0xbc, 0x83, 0xa4, 0x1f, 0x6c, 0x1e, 0x82, 0xca, 0x67, 0x2c, 0x2d, 0xe, 0x25, 0x31, 0x67, 0x6a, 0x51, 0x99, 0xc0, 0xc8, 0xbe, 0x35, 0xcc, 0x45, 0xc, 0xca, 0xdc, 0x1c, 0x6, 0x70, 0x8f, 0xa1, 0xd7, 0x36, 0x13, 0xe8, 0xb5, 0x6d, 0x18, 0x6b, 0xb3, 0xf8, 0x65, 0xe6, 0xb, 0x36, 0x5c, 0x24, 0xde, 0x86, 0x96, 0x3a, 0xaf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_cursor_unfocus_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xbf, 0xb5, 0xb1, 0xc0, 0xb5, 0xb2, 0xc3, 0xb8, 0xb5, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc5, 0xba, 0xb7, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xba, 0xb7, 0xc5, 0xba, 0xb7, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xca, 0xc1, 0xbe, 0xca, 0xc1, 0xbe, 0xcd, 0xc4, 0xc1, 0xcd, 0xc6, 0xc3, 0xd0, 0xc9, 0xc6, 0xcf, 0xc8, 0xc5, 0xd2, 0xcb, 0xc8, 0xd3, 0xcb, 0xc9, 0xd3, 0xcc, 0xc9, 0xd5, 0xcd, 0xcb, 0xd4, 0xcc, 0xca, 0xd7, 0xd1, 0xcf, 0xd6, 0xd0, 0xce, 0xda, 0xd4, 0xd2, 0xdd, 0xd7, 0xd5, 0xdd, 0xd7, 0xd5, 0x9a, 0x8b, 0x86, 0x94, 0x85, 0x80, 0x8e, 0x80, 0x7a, 0x88, 0x79, 0x74, 0x81, 0x75, 0x6f, 0x7a, 0x6f, 0x6a, 0x73, 0x69, 0x65, 0x0, 0x0, 0x0, 0xfb, 0x87, 0x71, 0x8e, 0x0, 0x0, 0x0, 0x2b, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x2f, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x82, 0xd8, 0x8a, 0x2f, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x32, 0x40, 0xd2, 0x4c, 0xc8, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x82, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0xcf, 0xe9, 0x16, 0xc1, 0x30, 0x14, 0x4, 0xe0, 0xb1, 0x96, 0x16, 0x25, 0x34, 0x84, 0x26, 0x2d, 0xaa, 0xb6, 0xac, 0xef, 0xff, 0x72, 0x6e, 0x38, 0xe, 0xfd, 0xe6, 0xce, 0x99, 0xdf, 0x17, 0xcf, 0xe, 0x68, 0xf4, 0x48, 0x7f, 0x40, 0x86, 0x23, 0xd, 0x33, 0x4e, 0x92, 0x64, 0x32, 0x4d, 0xb3, 0x2c, 0x9d, 0xcd, 0xd, 0xec, 0x22, 0xcf, 0xf3, 0xe5, 0x8a, 0xb1, 0x35, 0x63, 0x1b, 0xb, 0x57, 0xf0, 0x82, 0x73, 0xbe, 0xdd, 0x9, 0x21, 0xf6, 0xe, 0xfe, 0xf0, 0x55, 0x96, 0xa5, 0x47, 0x90, 0x91, 0x52, 0x4a, 0x2a, 0x29, 0x3, 0x42, 0x55, 0x93, 0xaa, 0x8e, 0x53, 0x5, 0xf8, 0x23, 0x39, 0x51, 0xcf, 0x14, 0xf, 0xd7, 0x44, 0x97, 0xf7, 0x35, 0xe, 0xb6, 0xbd, 0xb6, 0x1f, 0xb4, 0x16, 0xe6, 0xf6, 0xc7, 0x40, 0xdf, 0x1f, 0x3f, 0x1a, 0xdd, 0x17, 0x5e, 0xc0, 0x36, 0x18, 0x83, 0x7f, 0x54, 0x76, 0x87, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xbf, 0xb5, 0xb1, 0xc0, 0xb5, 0xb2, 0xc3, 0xb8, 0xb5, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc5, 0xba, 0xb7, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xba, 0xb7, 0xc5, 0xba, 0xb7, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xca, 0xc1, 0xbe, 0xca, 0xc1, 0xbe, 0xcd, 0xc4, 0xc1, 0xcd, 0xc6, 0xc3, 0xd0, 0xc9, 0xc6, 0xcf, 0xc8, 0xc5, 0xd2, 0xcb, 0xc8, 0xd3, 0xcb, 0xc9, 0xd3, 0xcc, 0xc9, 0xd5, 0xcd, 0xcb, 0xd4, 0xcc, 0xca, 0xd7, 0xd1, 0xcf, 0xd6, 0xd0, 0xce, 0xda, 0xd4, 0xd2, 0xdd, 0xd7, 0xd5, 0xdd, 0xd7, 0xd5, 0x9a, 0x8b, 0x86, 0x94, 0x85, 0x80, 0x8e, 0x80, 0x7a, 0x88, 0x79, 0x74, 0x81, 0x75, 0x6f, 0x7a, 0x6f, 0x6a, 0x73, 0x69, 0x65, 0x9a, 0x51, 0xd2, 0xe3, 0x0, 0x0, 0x0, 0x2b, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x2f, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x82, 0xd8, 0x8a, 0x2f, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0xd1, 0x66, 0x40, 0x6, 0x2c, 0x8c, 0x57, 0x0, 0x2d, 0xc9, 0x87, 0x15, 0x4, 0x51, 0x8, 0x42, 0xd1, 0x7, 0x13, 0x3b, 0xd9, 0xfe, 0x1b, 0x1c, 0x16, 0xcf, 0xf, 0xa6, 0xab, 0x6a, 0xd3, 0x2a, 0xbf, 0x53, 0xb7, 0x66, 0xa8, 0x63, 0xe9, 0xd4, 0xbb, 0x88, 0x82, 0xcb, 0x47, 0xd9, 0xb, 0x54, 0xde, 0xec, 0x57, 0x97, 0xde, 0x63, 0x94, 0x12, 0xab, 0xec, 0xec, 0x56, 0xce, 0x69, 0x28, 0xc8, 0x9f, 0xbf, 0x9c, 0x39, 0xd8, 0x16, 0x47, 0x69, 0x65, 0xc, 0xe, 0xc3, 0x8e, 0xeb, 0x69, 0x28, 0x1, 0x0, 0xb0, 0xae, 0x0, 0x0, 0x90, 0x3f, 0xa6, 0x5b, 0x1b, 0xad, 0x12, 0x69, 0xd7, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_title_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x23, 0x25, 0x4c, 0x4a, 0x4e, 0x1, 0xf9, 0x98, 0x2e, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x20, 0xd, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0xc7, 0xaa, 0x85, 0x8e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x23, 0x25, 0x4c, 0x4a, 0x4e, 0x1, 0xf9, 0x98, 0x2e, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x6e, 0xa6, 0xf, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tree_title_pressed_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x36, 0x34, 0x36, 0x4c, 0x4a, 0x4e, 0x14, 0xd7, 0x5b, 0xf8, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x20, 0xd, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0xc7, 0xaa, 0x85, 0x8e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x36, 0x34, 0x36, 0x4c, 0x4a, 0x4e, 0x14, 0xd7, 0x5b, 0xf8, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x6e, 0xa6, 0xf, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char unchecked_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xff, 0xff, 0xff, 0xf7, 0x93, 0x46, 0x7a, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x11, 0xe2, 0xb5, 0x3d, 0xba, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x53, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xb5, 0xcf, 0xc1, 0x12, 0x80, 0x20, 0x8, 0x45, 0x51, 0x5, 0x14, 0xd, 0x5, 0xff, 0xff, 0x6b, 0x23, 0x27, 0x67, 0x9a, 0x6c, 0xdb, 0x5d, 0x9e, 0xd, 0x8f, 0x10, 0xb6, 0x22, 0x20, 0xa5, 0x19, 0x21, 0x44, 0x7, 0xc8, 0x2c, 0x6d, 0x26, 0x9c, 0xc1, 0x1, 0xb9, 0xab, 0xcd, 0xb4, 0x33, 0x3a, 0x90, 0xe8, 0xb8, 0x53, 0x21, 0x87, 0xd4, 0x6c, 0x81, 0xb5, 0xf4, 0x17, 0x6c, 0x67, 0x9f, 0xc3, 0xca, 0x35, 0xc, 0x6a, 0x59, 0xd3, 0x8f, 0xa, 0x5f, 0xcf, 0xbd, 0x3a, 0x1, 0x93, 0xe2, 0x8, 0xa4, 0xb1, 0xeb, 0xd3, 0x56, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x23, 0xc3, 0x49, 0x39, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0xcf, 0x45, 0x2, 0x80, 0x40, 0x8, 0x0, 0x40, 0x97, 0x66, 0xfb, 0xff, 0x9f, 0xb5, 0xdb, 0xb3, 0x73, 0xa4, 0x19, 0xbe, 0x2, 0x20, 0xf1, 0x8a, 0x10, 0xc2, 0x1c, 0x0, 0xd1, 0x94, 0x57, 0x49, 0x5, 0xe6, 0x0, 0x6a, 0xa9, 0x6d, 0x55, 0x8b, 0xe2, 0x1c, 0xa0, 0x54, 0xfb, 0xae, 0x26, 0x9a, 0x3, 0x9c, 0xdb, 0x11, 0x68, 0x99, 0xff, 0xa, 0x7c, 0xd6, 0xde, 0xf, 0x33, 0x9c, 0x3, 0xe0, 0x76, 0x9c, 0x1e, 0x1d, 0xbe, 0xcf, 0x7d, 0x4c, 0x93, 0xe2, 0x8, 0xa4, 0x66, 0x3c, 0xec, 0xed, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char updown_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x2b, 0x8a, 0x3e, 0x7d, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xa6, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xa5, 0x90, 0x21, 0xe, 0xc2, 0x50, 0x10, 0x44, 0xdf, 0x27, 0x9b, 0x10, 0x2e, 0xc0, 0x9, 0xd6, 0x81, 0xe3, 0x6, 0xe0, 0xa0, 0xd7, 0x2d, 0xae, 0x18, 0x24, 0x95, 0xc5, 0x7d, 0x51, 0xdd, 0xb, 0x60, 0xf6, 0x67, 0x31, 0xfb, 0x49, 0xc1, 0x20, 0x3a, 0x6a, 0x93, 0x99, 0x9d, 0xcc, 0xc, 0x2c, 0x45, 0xaa, 0x47, 0xce, 0x79, 0x2b, 0x22, 0x2d, 0x80, 0x99, 0x5d, 0x54, 0x75, 0xfa, 0x8, 0x82, 0xec, 0x80, 0x7d, 0xe8, 0x7, 0x33, 0x3b, 0xa9, 0xea, 0x94, 0x82, 0xbc, 0x1, 0x3b, 0x60, 0x8, 0xc1, 0x1e, 0x78, 0x9a, 0xd9, 0x51, 0xc2, 0x76, 0x57, 0xbf, 0x0, 0xaa, 0x9b, 0x88, 0xb4, 0x2b, 0x77, 0x7f, 0x1, 0x7d, 0xb5, 0x54, 0xd5, 0x29, 0x84, 0x7d, 0x70, 0x4b, 0x6b, 0x8e, 0xe3, 0x78, 0x7, 0x36, 0x66, 0x76, 0xae, 0xd5, 0x22, 0xf8, 0x15, 0x78, 0x89, 0xbb, 0xaf, 0x53, 0x4a, 0x7, 0x11, 0xe9, 0x72, 0xce, 0x5f, 0x21, 0xdd, 0xfd, 0x21, 0xa5, 0x94, 0x66, 0x96, 0xba, 0x9b, 0xd5, 0x1c, 0x4a, 0x29, 0xcd, 0xff, 0xa1, 0x7e, 0xa6, 0xbe, 0xc6, 0xd4, 0x9f, 0x3c, 0xcb, 0xf1, 0x6, 0x8e, 0x4e, 0x65, 0x44, 0x6f, 0x74, 0x5c, 0xa1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0x81, 0x83, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0x4e, 0xb5, 0x1, 0xc0, 0x30, 0xc, 0xf3, 0x15, 0xfe, 0xff, 0x96, 0x64, 0xa, 0x6c, 0xca, 0x56, 0xd2, 0x25, 0x65, 0xe6, 0xc8, 0x8b, 0x49, 0x20, 0x79, 0x28, 0x95, 0x81, 0xa1, 0xd4, 0x7d, 0x4, 0xbb, 0xa1, 0x50, 0xea, 0x3c, 0xa6, 0x71, 0x98, 0x96, 0x69, 0x58, 0x31, 0xcc, 0xb7, 0xe5, 0x2f, 0x48, 0x63, 0x26, 0xf6, 0xa2, 0xd4, 0x18, 0xf9, 0x7, 0x2d, 0xe3, 0x46, 0x89, 0xb4, 0xd2, 0xf8, 0xa3, 0x68, 0xe3, 0xd7, 0x14, 0x20, 0xe6, 0xc3, 0x3d, 0xd8, 0xca, 0x5e, 0x94, 0x32, 0xd0, 0x3, 0x91, 0xba, 0x5f, 0x1b, 0x4a, 0x9b, 0x12, 0x62, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vseparator_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x3, 0x11, 0xc, 0x4c, 0xf2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x80, 0x81, 0xac, 0x95, 0xc, 0x48, 0x0, 0x0, 0xe, 0x79, 0x1, 0x14, 0xa1, 0xc9, 0x59, 0x2, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xeb, 0x64, 0x9a, 0x78, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0xf, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x80, 0x83, 0xac, 0x95, 0xc, 0x48, 0x0, 0x0, 0xe, 0x79, 0x1, 0x14, 0x17, 0x9a, 0x55, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vslider_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x54, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x34, 0x33, 0x3a, 0x2d, 0x2c, 0x32, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x40, 0x3e, 0x4a, 0x20, 0x20, 0x24, 0x34, 0x33, 0x3a, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x27, 0x2d, 0x2c, 0x32, 0x1f, 0x1f, 0x23, 0xff, 0xff, 0xff, 0x3, 0x35, 0xf1, 0x5f, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1a, 0x40, 0x5d, 0x19, 0x28, 0x96, 0xf0, 0xfd, 0x94, 0x95, 0xfc, 0x93, 0xfc, 0xc0, 0x0, 0xb4, 0xa, 0x5f, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1b, 0x2, 0x60, 0xd4, 0xa4, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x9d, 0xcf, 0x39, 0x2, 0x80, 0x20, 0x10, 0x3, 0xc0, 0xe5, 0x90, 0x43, 0x50, 0x94, 0x1b, 0xfe, 0xff, 0x50, 0x5, 0x69, 0x94, 0xce, 0x94, 0x53, 0xec, 0x26, 0x0, 0x0, 0x88, 0x2e, 0x8c, 0x73, 0x26, 0x28, 0x82, 0x1e, 0x44, 0xe5, 0xaa, 0xb4, 0x56, 0x9b, 0x1c, 0x82, 0xc4, 0x6e, 0x9c, 0xf7, 0xce, 0x1c, 0x62, 0x0, 0x53, 0x2e, 0xc4, 0x18, 0x9c, 0x62, 0x3, 0xb8, 0xf6, 0xf1, 0x8e, 0x3f, 0xf9, 0x3, 0xd8, 0xa6, 0xdc, 0x20, 0x27, 0x8b, 0x3b, 0x90, 0x52, 0x43, 0x83, 0x50, 0xb, 0xf9, 0xb, 0xd3, 0xd1, 0xe9, 0xed, 0x5c, 0x6c, 0xaa, 0xfe, 0x1d, 0xf7, 0x9e, 0x7f, 0x1, 0x89, 0x5c, 0xa, 0x6b, 0x1f, 0xe5, 0xca, 0x60, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x51, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x34, 0x33, 0x3a, 0x2d, 0x2c, 0x32, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x40, 0x3e, 0x4a, 0x20, 0x20, 0x24, 0x34, 0x33, 0x3a, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x27, 0x2d, 0x2c, 0x32, 0x1f, 0x1f, 0x23, 0x30, 0x7, 0x9c, 0xfe, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1a, 0x40, 0x5d, 0x19, 0x28, 0x96, 0xf0, 0xfd, 0x94, 0x95, 0xfc, 0x93, 0xfc, 0xc0, 0x0, 0xb4, 0xa, 0x5f, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2c, 0xc8, 0x83, 0x11, 0x0, 0x30, 0x0, 0xc0, 0xc0, 0xda, 0xf6, 0xfe, 0x8b, 0xd6, 0x39, 0xe6, 0xc1, 0xe, 0x12, 0xca, 0x38, 0x67, 0x82, 0xc0, 0x73, 0xe7, 0xa5, 0xd2, 0xc6, 0x68, 0x2b, 0xbf, 0x40, 0xe1, 0x7c, 0x2e, 0x25, 0xfb, 0x20, 0x3e, 0x30, 0x9d, 0x6b, 0x6b, 0x35, 0x6b, 0xf6, 0x81, 0x9b, 0xd2, 0x76, 0x25, 0xf2, 0x7, 0x28, 0xf5, 0x71, 0x60, 0xf4, 0x84, 0x2e, 0xe0, 0x35, 0x49, 0x29, 0x51, 0x90, 0x80, 0xa8, 0x94, 0x24, 0x33, 0x19, 0x2, 0x18, 0x86, 0xa2, 0x5b, 0x8b, 0xe9, 0x30, 0x4c, 0xa7, 0x63, 0x7a, 0xe, 0xc3, 0xfb, 0x0, 0x89, 0x5c, 0xa, 0x6b, 0x4f, 0x78, 0xac, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vslider_grabber_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xb7, 0xff, 0x88, 0x5, 0x1d, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x1, 0x12, 0x1, 0x36, 0x8, 0x50, 0xb9, 0xa7, 0x53, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0xf6, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0xbd, 0x90, 0xb1, 0x4a, 0x42, 0x51, 0x0, 0x86, 0xbf, 0x73, 0x8e, 0x71, 0xe5, 0x9a, 0x5c, 0x41, 0xd0, 0x66, 0x6b, 0x33, 0x1c, 0x7c, 0x80, 0xa0, 0xa5, 0x17, 0x8, 0xa2, 0x2d, 0x84, 0xf0, 0x1, 0xa2, 0x25, 0xf1, 0x9, 0x9a, 0x1c, 0xda, 0x5b, 0xb2, 0x47, 0xa8, 0xa5, 0xc1, 0xa0, 0x51, 0x88, 0xa2, 0x29, 0xa, 0xc1, 0x84, 0x8, 0x43, 0xf4, 0x96, 0x17, 0xcf, 0xed, 0xde, 0x73, 0x9c, 0xcc, 0x5c, 0xda, 0xea, 0x9f, 0x3f, 0xfe, 0x9f, 0xef, 0x87, 0x3f, 0x8f, 0x0, 0x40, 0xe1, 0xe2, 0x91, 0x42, 0x10, 0x32, 0xe6, 0x3, 0x8d, 0xc1, 0xce, 0x1, 0x45, 0xb6, 0xba, 0xbb, 0xba, 0xed, 0x95, 0x8c, 0xd0, 0x7d, 0xff, 0xe1, 0xee, 0xe2, 0xb6, 0xdd, 0x79, 0x61, 0xc4, 0xd7, 0xc, 0x48, 0x57, 0x2b, 0xeb, 0xb5, 0x28, 0xaf, 0x1, 0xc5, 0x12, 0x4e, 0xac, 0x7b, 0x6f, 0x57, 0x27, 0x8d, 0xcf, 0xe, 0x1, 0x56, 0x1, 0xb9, 0x9d, 0xba, 0x28, 0x6, 0x18, 0xc, 0x31, 0x21, 0x5a, 0xda, 0x4c, 0xb6, 0xbc, 0xb9, 0x35, 0x7c, 0xea, 0xbd, 0x13, 0x4a, 0x20, 0xe5, 0x95, 0xf4, 0x6c, 0x12, 0x30, 0x84, 0xf8, 0x44, 0x6b, 0xfb, 0xcd, 0x83, 0x3d, 0x1c, 0xf9, 0x8b, 0x80, 0x4a, 0xba, 0x88, 0x4, 0x30, 0x1e, 0xdd, 0x3b, 0x1b, 0xf1, 0x77, 0x87, 0x24, 0x81, 0x8b, 0x79, 0x3e, 0x3b, 0x6a, 0x5d, 0x33, 0x51, 0x80, 0x2d, 0x38, 0x2b, 0x65, 0xb5, 0x6c, 0x91, 0x28, 0x92, 0xa4, 0xad, 0xec, 0x76, 0xcf, 0x8f, 0xf, 0x1f, 0xdb, 0xc, 0x31, 0xb, 0x9a, 0xb1, 0xd0, 0x3, 0xfb, 0xda, 0x3a, 0xbd, 0xbc, 0x89, 0xfa, 0xf8, 0x73, 0xcd, 0x9f, 0x47, 0x45, 0x4, 0xf8, 0x4, 0x18, 0xfe, 0x2f, 0x53, 0x8, 0x62, 0x5c, 0xcf, 0x1f, 0x5f, 0xcb, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xbc, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x17, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0xd2, 0xf2, 0x3a, 0xf, 0xce, 0x78, 0x3f, 0xed, 0x43, 0xff, 0xed, 0xc6, 0xf5, 0x41, 0xa9, 0x8a, 0x86, 0xc, 0x22, 0xc, 0xac, 0x8, 0x5, 0xbc, 0x69, 0x79, 0x93, 0x5e, 0xf4, 0xfd, 0x6f, 0x7, 0xc2, 0xae, 0xff, 0xfd, 0xff, 0xa7, 0xfd, 0xe9, 0x7f, 0x50, 0x31, 0x87, 0x47, 0x87, 0x81, 0x1b, 0x66, 0x8e, 0x4c, 0xe7, 0xc1, 0xbe, 0xff, 0x2d, 0xff, 0x9b, 0xa1, 0xb0, 0xf5, 0x7f, 0xe7, 0xff, 0xc9, 0xff, 0x27, 0xdc, 0xb6, 0xf0, 0x7, 0x9a, 0xc3, 0x2, 0x52, 0xa0, 0x3e, 0xe3, 0x7d, 0x3b, 0x54, 0x12, 0xa1, 0xa8, 0xe7, 0xff, 0x9c, 0x2f, 0x45, 0xc5, 0xc, 0xdc, 0xf8, 0x14, 0x7c, 0xaf, 0xaa, 0x65, 0xe0, 0xc1, 0x69, 0xc5, 0xc4, 0x3b, 0xe, 0xa1, 0xc, 0x62, 0xc, 0x2c, 0x68, 0x8e, 0xec, 0xf8, 0xdf, 0xfb, 0x7f, 0xda, 0xbf, 0x89, 0xf, 0x4a, 0xa6, 0xf2, 0xe8, 0x0, 0x75, 0x33, 0xa2, 0x79, 0x73, 0xea, 0x87, 0xbe, 0x7b, 0xbd, 0x47, 0x7d, 0x53, 0x58, 0x34, 0x18, 0x84, 0x19, 0x58, 0xb1, 0x7, 0x94, 0xa, 0x83, 0x14, 0x50, 0x27, 0x13, 0x3, 0x3d, 0x1, 0x0, 0x79, 0xc3, 0x79, 0x54, 0x19, 0x56, 0x3b, 0x28, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vslider_grabber_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x7, 0xa, 0x13, 0x2e, 0x39, 0x86, 0x33, 0xc2, 0xfe, 0x0, 0x0, 0x0, 0x1d, 0x69, 0x54, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x64, 0x2e, 0x65, 0x7, 0x0, 0x0, 0x0, 0xb7, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0xa0, 0x13, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0x8c, 0xf3, 0x5c, 0xf, 0xfa, 0xbc, 0xf7, 0xfe, 0xe0, 0x71, 0xdb, 0x71, 0xbd, 0x66, 0xaa, 0xa0, 0x21, 0x83, 0x8, 0x3, 0x2b, 0x42, 0x1, 0xaf, 0x71, 0x9e, 0xe7, 0xb, 0xf7, 0xff, 0x2e, 0x40, 0xe8, 0xfa, 0xdf, 0xe3, 0xbf, 0xf7, 0x1f, 0x8f, 0x7, 0x36, 0x73, 0xd8, 0x74, 0x18, 0xb8, 0x61, 0xe6, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x87, 0xce, 0x40, 0x65, 0x5e, 0xff, 0x3d, 0x6e, 0xcb, 0xf8, 0x3, 0xcd, 0x61, 0x1, 0x29, 0x50, 0xf7, 0x79, 0xef, 0x82, 0xa4, 0x0, 0xa2, 0xc8, 0xed, 0xbf, 0xdf, 0x17, 0xcb, 0x62, 0xa0, 0x29, 0x78, 0x14, 0x7c, 0xb7, 0xad, 0x65, 0xe0, 0xc1, 0x69, 0x85, 0xe7, 0x1d, 0x85, 0x50, 0x6, 0x31, 0x88, 0x15, 0x48, 0x8e, 0x74, 0xf9, 0xef, 0xfe, 0xdf, 0xfb, 0x9f, 0xe7, 0x3, 0xab, 0xa9, 0x40, 0x47, 0xf2, 0xc0, 0x1c, 0x89, 0xe4, 0x4d, 0xf7, 0x7b, 0xee, 0x47, 0xd5, 0x53, 0x98, 0x34, 0x18, 0x84, 0x91, 0xbd, 0x89, 0x1c, 0x50, 0x2a, 0xc, 0x52, 0x40, 0x9d, 0x4c, 0xc, 0xf4, 0x4, 0x0, 0xf1, 0x9, 0x63, 0x9b, 0x3e, 0x2a, 0x19, 0x52, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xb4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x17, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0x8c, 0xf3, 0x5c, 0xf, 0xfa, 0xbc, 0xf7, 0xfe, 0xe0, 0x71, 0xdb, 0x71, 0xbd, 0x66, 0xaa, 0xa0, 0x21, 0x83, 0x8, 0x3, 0x2b, 0x42, 0x1, 0xaf, 0x71, 0x9e, 0xe7, 0xb, 0xf7, 0xff, 0x2e, 0x40, 0xe8, 0xfa, 0xdf, 0xe3, 0xbf, 0xf7, 0x1f, 0x8f, 0x7, 0x36, 0x73, 0xd8, 0x74, 0x18, 0xb8, 0x61, 0xe6, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x87, 0xce, 0x40, 0x65, 0x5e, 0xff, 0x3d, 0x6e, 0xcb, 0xf8, 0x3, 0xcd, 0x61, 0x1, 0x29, 0x50, 0xf7, 0x79, 0xef, 0x2, 0x95, 0x44, 0x28, 0x72, 0xfb, 0xef, 0xf7, 0xc5, 0xb2, 0x98, 0x81, 0x1b, 0x9f, 0x82, 0xef, 0xb6, 0xb5, 0xc, 0x3c, 0x38, 0xad, 0xf0, 0xbc, 0xa3, 0x10, 0xca, 0x20, 0xc6, 0xc0, 0x82, 0xec, 0x48, 0x30, 0x74, 0xff, 0xef, 0xfd, 0xcf, 0xf3, 0x81, 0xd5, 0x54, 0x36, 0x1d, 0xa0, 0x6e, 0x46, 0xc, 0x6f, 0xba, 0xdf, 0x73, 0x3f, 0xaa, 0x9e, 0xc2, 0xa4, 0xc1, 0x20, 0xcc, 0xc0, 0x8a, 0x3d, 0xa0, 0x54, 0x18, 0xa4, 0x80, 0x3a, 0x99, 0x18, 0xe8, 0x9, 0x0, 0xf1, 0x9, 0x63, 0x9b, 0x53, 0x7f, 0x6d, 0x9b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vslider_grabber_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x3a, 0x69, 0x69, 0x5b, 0xa6, 0xa5, 0x61, 0xb3, 0xbc, 0x63, 0xb7, 0xc8, 0x65, 0xbb, 0xca, 0x60, 0xaf, 0xb1, 0x48, 0x83, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x55, 0x9b, 0x9a, 0x60, 0xb2, 0xbd, 0x5e, 0xb1, 0xcd, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x62, 0xb4, 0xbd, 0x51, 0x93, 0x92, 0x68, 0xc0, 0xcf, 0x0, 0x0, 0x0, 0x56, 0x9d, 0x9c, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x63, 0xb7, 0xbf, 0x52, 0x96, 0x95, 0x62, 0xb3, 0xbf, 0x5e, 0xb0, 0xcd, 0x0, 0x0, 0x0, 0x3, 0x5, 0x5, 0x36, 0x63, 0x63, 0x63, 0xb4, 0xb6, 0x60, 0xb1, 0xbc, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0xa3, 0xc8, 0x4f, 0x98, 0xc4, 0x4b, 0x93, 0xc2, 0x4c, 0x94, 0xc2, 0x54, 0xa2, 0xc8, 0x5a, 0xab, 0xcb, 0x4e, 0x97, 0xc4, 0x49, 0x8f, 0xc0, 0x47, 0x8c, 0xbf, 0x48, 0x8e, 0xc0, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0x5a, 0xac, 0xcc, 0x53, 0x9f, 0xc7, 0x4d, 0x96, 0xc3, 0x4b, 0x92, 0xc2, 0xff, 0xff, 0xff, 0x76, 0xbd, 0x27, 0x7a, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x88, 0x5, 0x1d, 0x48, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x1, 0x12, 0x1, 0x36, 0x11, 0x34, 0xd2, 0xf, 0x93, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x48, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0xa0, 0x12, 0x10, 0x14, 0xe0, 0xe7, 0xe3, 0x45, 0xe2, 0x4b, 0x9a, 0x18, 0x1b, 0x19, 0x1a, 0x48, 0x88, 0x8b, 0xc1, 0xe4, 0x4d, 0x2c, 0x2d, 0x80, 0xc0, 0xdc, 0xcc, 0x54, 0x6, 0x22, 0x20, 0x60, 0x6c, 0x1, 0x1, 0xe6, 0x56, 0x72, 0x68, 0x2, 0xd6, 0x8a, 0xa8, 0x5a, 0x6c, 0x94, 0x11, 0x86, 0xda, 0xdb, 0xd9, 0xaa, 0xa9, 0xaa, 0x20, 0x59, 0xab, 0xa3, 0xad, 0xc5, 0x40, 0x3d, 0x0, 0x0, 0xbf, 0x8e, 0xc, 0xed, 0xed, 0xc7, 0x67, 0x72, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x6c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x61, 0xb3, 0xbc, 0x63, 0xb7, 0xc8, 0x65, 0xbb, 0xca, 0x60, 0xaf, 0xb1, 0x55, 0x9b, 0x9a, 0x60, 0xb2, 0xbd, 0x5e, 0xb1, 0xcd, 0x61, 0xb3, 0xc2, 0x62, 0xb4, 0xbd, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x63, 0xb7, 0xbf, 0x52, 0x96, 0x95, 0x62, 0xb3, 0xbf, 0x5e, 0xb0, 0xcd, 0x63, 0xb4, 0xb6, 0x60, 0xb1, 0xbc, 0x63, 0xb7, 0xc7, 0x55, 0xa3, 0xc8, 0x4f, 0x98, 0xc4, 0x4b, 0x93, 0xc2, 0x4c, 0x94, 0xc2, 0x54, 0xa2, 0xc8, 0x5a, 0xab, 0xcb, 0x4e, 0x97, 0xc4, 0x49, 0x8f, 0xc0, 0x47, 0x8c, 0xbf, 0x48, 0x8e, 0xc0, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0x5a, 0xac, 0xcc, 0x53, 0x9f, 0xc7, 0x4d, 0x96, 0xc3, 0x4b, 0x92, 0xc2, 0x7f, 0xcb, 0x5d, 0x16, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0x60, 0x65, 0x61, 0x66, 0x62, 0x44, 0xe2, 0x73, 0x4a, 0x88, 0x8b, 0x89, 0x8a, 0x70, 0xb0, 0xb3, 0xc1, 0xe4, 0x25, 0x64, 0x65, 0x80, 0x40, 0x5a, 0x4a, 0x92, 0xb, 0x22, 0xc0, 0x22, 0x2e, 0x3, 0x1, 0xd2, 0x72, 0xdc, 0x68, 0x2, 0xf2, 0x3c, 0xa8, 0x5a, 0x14, 0x78, 0x11, 0x86, 0x2a, 0x2b, 0x29, 0xa, 0xf0, 0xf3, 0x21, 0x59, 0x2b, 0x2c, 0x24, 0xc8, 0x40, 0x3d, 0x0, 0x0, 0x19, 0x8b, 0x5, 0xfc, 0x96, 0x5c, 0x15, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vslider_tick_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x4, 0x3, 0x0, 0x0, 0x0, 0x75, 0x9a, 0xa2, 0xdf, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x1e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x81, 0xa2, 0xad, 0x8c, 0xac, 0xb8, 0x38, 0x55, 0x5f, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0xff, 0xff, 0xff, 0xe1, 0x56, 0x59, 0xc8, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x79, 0x79, 0x31, 0x1c, 0x18, 0xed, 0xfe, 0x2b, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x9, 0xf1, 0xd9, 0xa5, 0xec, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x80, 0x1, 0xd7, 0x44, 0x5, 0x6, 0x6, 0xe6, 0x92, 0x30, 0x86, 0xf2, 0x62, 0x3, 0x20, 0xa3, 0xbd, 0x1c, 0x2e, 0x3, 0x0, 0x3f, 0xce, 0x3, 0xaf, 0xf9, 0x94, 0x50, 0x96, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x4, 0x3, 0x0, 0x0, 0x0, 0x75, 0x9a, 0xa2, 0xdf, 0x0, 0x0, 0x0, 0x1b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x81, 0xa2, 0xad, 0x8c, 0xac, 0xb8, 0x38, 0x55, 0x5f, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x7c, 0xda, 0x48, 0x6d, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x79, 0x79, 0x31, 0x1c, 0x18, 0xed, 0xfe, 0x2b, 0x0, 0x0, 0x0, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x80, 0x3, 0xd7, 0x44, 0x5, 0x6, 0x6, 0xe6, 0x92, 0x30, 0x86, 0xf2, 0x62, 0x3, 0x20, 0xa3, 0xbd, 0x1c, 0x2e, 0x3, 0x0, 0x3f, 0xce, 0x3, 0xaf, 0xed, 0xed, 0x7c, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vsplit_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char vsplitter_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x9, 0xa6, 0x3, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0xa0, 0x10, 0x30, 0x33, 0x2c, 0x10, 0x3d, 0x47, 0x9, 0x66, 0x66, 0x10, 0xbd, 0xf6, 0x98, 0x22, 0x3c, 0xe0, 0x60, 0x18, 0x84, 0x1, 0x0, 0x59, 0x34, 0x6a, 0x2d, 0x64, 0xeb, 0x72, 0x24, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x9, 0xa6, 0x3, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x18, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x1c, 0x2c, 0x48, 0xa5, 0xc, 0x33, 0xa4, 0x5a, 0x53, 0x86, 0x29, 0x7, 0xa3, 0x61, 0x0, 0x0, 0x18, 0x61, 0x34, 0xa1, 0xba, 0xa4, 0x4d, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char window_resizer_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x19, 0x11, 0x33, 0x13, 0xaa, 0xc0, 0xf, 0x5f, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x63, 0x60, 0x18, 0x5, 0x24, 0x81, 0x17, 0x2f, 0x5e, 0xf4, 0xa3, 0x8b, 0x31, 0x91, 0xa2, 0xb9, 0xb9, 0xb9, 0x99, 0x7c, 0x9b, 0xb3, 0xb3, 0xb3, 0xfb, 0x87, 0x81, 0x66, 0x6c, 0x81, 0x48, 0x92, 0x66, 0xa2, 0x5c, 0x43, 0x91, 0xe6, 0x11, 0xa, 0x0, 0x73, 0x5b, 0x34, 0x19, 0x10, 0xa0, 0xb6, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0xbc, 0xe0, 0x45, 0x3f, 0x1, 0xe9, 0xec, 0xfe, 0x81, 0x94, 0x86, 0xb1, 0x70, 0x48, 0x23, 0x58, 0x84, 0xa4, 0x7, 0x15, 0x0, 0x0, 0xed, 0x9f, 0x18, 0xe8, 0xcd, 0x91, 0xd8, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
// shaders block
diff --git a/scene/resources/default_theme/toggle_off.png b/scene/resources/default_theme/toggle_off.png
index 71cd64b001..64b51c8c9d 100644
--- a/scene/resources/default_theme/toggle_off.png
+++ b/scene/resources/default_theme/toggle_off.png
Binary files differ
diff --git a/scene/resources/default_theme/toggle_on.png b/scene/resources/default_theme/toggle_on.png
index 6ea1b589c7..f0c699c181 100644
--- a/scene/resources/default_theme/toggle_on.png
+++ b/scene/resources/default_theme/toggle_on.png
Binary files differ
diff --git a/scene/resources/default_theme/tool_button_pressed.png b/scene/resources/default_theme/tool_button_pressed.png
index bcf70b486d..5494475792 100644
--- a/scene/resources/default_theme/tool_button_pressed.png
+++ b/scene/resources/default_theme/tool_button_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/tooltip_bg.png b/scene/resources/default_theme/tooltip_bg.png
index eca0675a98..07b7d942ca 100644
--- a/scene/resources/default_theme/tooltip_bg.png
+++ b/scene/resources/default_theme/tooltip_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_bg.png b/scene/resources/default_theme/tree_bg.png
index 839a6a272a..2b0c506f34 100644
--- a/scene/resources/default_theme/tree_bg.png
+++ b/scene/resources/default_theme/tree_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_bg_disabled.png b/scene/resources/default_theme/tree_bg_disabled.png
index a0fa505e4c..69d78febd9 100644
--- a/scene/resources/default_theme/tree_bg_disabled.png
+++ b/scene/resources/default_theme/tree_bg_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_bg_focus.png b/scene/resources/default_theme/tree_bg_focus.png
index 692cf71926..aadc6b0db4 100644
--- a/scene/resources/default_theme/tree_bg_focus.png
+++ b/scene/resources/default_theme/tree_bg_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_cursor.png b/scene/resources/default_theme/tree_cursor.png
index 94d2a08818..2b8722d066 100644
--- a/scene/resources/default_theme/tree_cursor.png
+++ b/scene/resources/default_theme/tree_cursor.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_cursor_unfocus.png b/scene/resources/default_theme/tree_cursor_unfocus.png
index 3f023bbabe..bfaebbea85 100644
--- a/scene/resources/default_theme/tree_cursor_unfocus.png
+++ b/scene/resources/default_theme/tree_cursor_unfocus.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_title.png b/scene/resources/default_theme/tree_title.png
index b0ddcffbbe..e5f3f49695 100644
--- a/scene/resources/default_theme/tree_title.png
+++ b/scene/resources/default_theme/tree_title.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_title_pressed.png b/scene/resources/default_theme/tree_title_pressed.png
index 746d10039e..35e2bb3008 100644
--- a/scene/resources/default_theme/tree_title_pressed.png
+++ b/scene/resources/default_theme/tree_title_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/unchecked.png b/scene/resources/default_theme/unchecked.png
index d6f790cbc2..8c818af755 100644
--- a/scene/resources/default_theme/unchecked.png
+++ b/scene/resources/default_theme/unchecked.png
Binary files differ
diff --git a/scene/resources/default_theme/updown.png b/scene/resources/default_theme/updown.png
index 916284a3cf..56f81921e8 100644
--- a/scene/resources/default_theme/updown.png
+++ b/scene/resources/default_theme/updown.png
Binary files differ
diff --git a/scene/resources/default_theme/vseparator.png b/scene/resources/default_theme/vseparator.png
index 498768c05b..51e79f3ac5 100644
--- a/scene/resources/default_theme/vseparator.png
+++ b/scene/resources/default_theme/vseparator.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_bg.png b/scene/resources/default_theme/vslider_bg.png
index 8d9ead3c5a..ba3244e3e5 100644
--- a/scene/resources/default_theme/vslider_bg.png
+++ b/scene/resources/default_theme/vslider_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_grabber.png b/scene/resources/default_theme/vslider_grabber.png
index afc490be45..6c6bf93e68 100644
--- a/scene/resources/default_theme/vslider_grabber.png
+++ b/scene/resources/default_theme/vslider_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_grabber_disabled.png b/scene/resources/default_theme/vslider_grabber_disabled.png
index c830359f45..49cced5055 100644
--- a/scene/resources/default_theme/vslider_grabber_disabled.png
+++ b/scene/resources/default_theme/vslider_grabber_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_grabber_hl.png b/scene/resources/default_theme/vslider_grabber_hl.png
index 548972e115..28774fdbf8 100644
--- a/scene/resources/default_theme/vslider_grabber_hl.png
+++ b/scene/resources/default_theme/vslider_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_tick.png b/scene/resources/default_theme/vslider_tick.png
index 873ebb00d8..bde788b563 100644
--- a/scene/resources/default_theme/vslider_tick.png
+++ b/scene/resources/default_theme/vslider_tick.png
Binary files differ
diff --git a/scene/resources/default_theme/vsplit_bg.png b/scene/resources/default_theme/vsplit_bg.png
index 7dd1d48b29..a5749f6d5c 100644
--- a/scene/resources/default_theme/vsplit_bg.png
+++ b/scene/resources/default_theme/vsplit_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/vsplitter.png b/scene/resources/default_theme/vsplitter.png
index ec5542bf69..dde1f390df 100644
--- a/scene/resources/default_theme/vsplitter.png
+++ b/scene/resources/default_theme/vsplitter.png
Binary files differ
diff --git a/scene/resources/default_theme/window_resizer.png b/scene/resources/default_theme/window_resizer.png
index ed51968c4e..b06e6f5366 100644
--- a/scene/resources/default_theme/window_resizer.png
+++ b/scene/resources/default_theme/window_resizer.png
Binary files differ
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 05493d5777..4df849df6a 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -211,9 +211,9 @@ Error DynamicFontAtSize::_load() {
scale_color_font = float(id.size) / face->available_sizes[i].width;
}
}
- error = FT_Select_Size(face, best_match);
+ FT_Select_Size(face, best_match);
} else {
- error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
+ FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
}
ascent = (face->size->metrics.ascender / 64.0) / oversampling * scale_color_font;
@@ -314,7 +314,7 @@ void DynamicFontAtSize::set_texture_flags(uint32_t p_flags) {
texture_flags = p_flags;
for (int i = 0; i < textures.size(); i++) {
- Ref<ImageTexture> &tex = textures[i].texture;
+ Ref<ImageTexture> &tex = textures.write[i].texture;
if (!tex.is_null())
tex->set_flags(p_flags);
}
@@ -400,7 +400,7 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp
for (int i = 0; i < textures.size(); i++) {
- CharTexture &ct = textures[i];
+ const CharTexture &ct = textures[i];
if (ct.texture->get_format() != p_image_format)
continue;
@@ -435,8 +435,6 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp
break;
}
- //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y));
-
if (ret.index == -1) {
//could not find texture to fit, create one
ret.x = 0;
@@ -466,7 +464,7 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp
}
tex.offsets.resize(texsize);
for (int i = 0; i < texsize; i++) //zero offsets
- tex.offsets[i] = 0;
+ tex.offsets.write[i] = 0;
textures.push_back(tex);
ret.index = textures.size() - 1;
@@ -493,7 +491,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b
//fit character in char texture
- CharTexture &tex = textures[tex_pos.index];
+ CharTexture &tex = textures.write[tex_pos.index];
{
PoolVector<uint8_t>::Write wr = tex.imgdata.write();
@@ -547,7 +545,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b
// update height array
for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- tex.offsets[k] = tex_pos.y + mh;
+ tex.offsets.write[k] = tex_pos.y + mh;
}
Character chr;
@@ -625,7 +623,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
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));
+ 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) | ft_hinting);
if (error) {
char_map[p_char] = character;
return;
@@ -698,9 +696,9 @@ void DynamicFont::_reload_cache() {
}
for (int i = 0; i < fallbacks.size(); i++) {
- fallback_data_at_size[i] = fallbacks[i]->_get_dynamic_font_at_size(cache_id);
+ fallback_data_at_size.write[i] = fallbacks.write[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);
+ fallback_outline_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(outline_cache_id);
}
emit_changed();
@@ -895,17 +893,17 @@ void DynamicFont::set_fallback(int p_idx, const Ref<DynamicFontData> &p_data) {
ERR_FAIL_COND(p_data.is_null());
ERR_FAIL_INDEX(p_idx, fallbacks.size());
- fallbacks[p_idx] = p_data;
- fallback_data_at_size[p_idx] = fallbacks[p_idx]->_get_dynamic_font_at_size(cache_id);
+ fallbacks.write[p_idx] = p_data;
+ fallback_data_at_size.write[p_idx] = fallbacks.write[p_idx]->_get_dynamic_font_at_size(cache_id);
}
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..
+ fallback_data_at_size.push_back(fallbacks.write[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));
+ fallback_outline_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(outline_cache_id));
_change_notify();
emit_changed();
@@ -1036,6 +1034,8 @@ SelfList<DynamicFont>::List DynamicFont::dynamic_fonts;
DynamicFont::DynamicFont() :
font_list(this) {
+ cache_id.size = 16;
+ outline_cache_id.size = 16;
spacing_top = 0;
spacing_bottom = 0;
spacing_char = 0;
@@ -1092,7 +1092,7 @@ void DynamicFont::update_oversampling() {
dynamic_font_mutex->unlock();
for (int i = 0; i < changed.size(); i++) {
- changed[i]->emit_changed();
+ changed.write[i]->emit_changed();
}
}
diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp
index 29f1106d16..be394e19c4 100644
--- a/scene/resources/dynamic_font_stb.cpp
+++ b/scene/resources/dynamic_font_stb.cpp
@@ -214,7 +214,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
int advance;
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 * scale;
@@ -279,8 +278,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
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) {
//could not find texture to fit, create one
tex_x = 0;
@@ -364,8 +361,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
chr.rect = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h);
- //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs));
-
char_map[p_char] = chr;
stbtt_FreeBitmap(cpbitmap, NULL);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 3fab4d3cfc..d3da842b79 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -378,7 +378,7 @@ bool Environment::is_ssr_rough() const {
void Environment::set_ssao_enabled(bool p_enable) {
ssao_enabled = p_enable;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
_change_notify();
}
@@ -390,7 +390,7 @@ bool Environment::is_ssao_enabled() const {
void Environment::set_ssao_radius(float p_radius) {
ssao_radius = p_radius;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_radius() const {
@@ -400,7 +400,7 @@ float Environment::get_ssao_radius() const {
void Environment::set_ssao_intensity(float p_intensity) {
ssao_intensity = p_intensity;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_intensity() const {
@@ -411,7 +411,7 @@ float Environment::get_ssao_intensity() const {
void Environment::set_ssao_radius2(float p_radius) {
ssao_radius2 = p_radius;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_radius2() const {
@@ -421,7 +421,7 @@ float Environment::get_ssao_radius2() const {
void Environment::set_ssao_intensity2(float p_intensity) {
ssao_intensity2 = p_intensity;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_intensity2() const {
@@ -431,7 +431,7 @@ float Environment::get_ssao_intensity2() const {
void Environment::set_ssao_bias(float p_bias) {
ssao_bias = p_bias;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_bias() const {
@@ -441,17 +441,27 @@ float Environment::get_ssao_bias() const {
void Environment::set_ssao_direct_light_affect(float p_direct_light_affect) {
ssao_direct_light_affect = p_direct_light_affect;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_direct_light_affect() const {
return ssao_direct_light_affect;
}
+void Environment::set_ssao_ao_channel_affect(float p_ao_channel_affect) {
+
+ ssao_ao_channel_affect = p_ao_channel_affect;
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+}
+float Environment::get_ssao_ao_channel_affect() const {
+
+ return ssao_ao_channel_affect;
+}
+
void Environment::set_ssao_color(const Color &p_color) {
ssao_color = p_color;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
Color Environment::get_ssao_color() const {
@@ -462,7 +472,7 @@ Color Environment::get_ssao_color() const {
void Environment::set_ssao_blur(SSAOBlur p_blur) {
ssao_blur = p_blur;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
Environment::SSAOBlur Environment::get_ssao_blur() const {
@@ -472,7 +482,7 @@ Environment::SSAOBlur Environment::get_ssao_blur() const {
void Environment::set_ssao_quality(SSAOQuality p_quality) {
ssao_quality = p_quality;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
Environment::SSAOQuality Environment::get_ssao_quality() const {
@@ -483,7 +493,7 @@ Environment::SSAOQuality Environment::get_ssao_quality() const {
void Environment::set_ssao_edge_sharpness(float p_edge_sharpness) {
ssao_edge_sharpness = p_edge_sharpness;
- VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
+ VS::get_singleton()->environment_set_ssao(environment, ssao_enabled, ssao_radius, ssao_intensity, ssao_radius2, ssao_intensity2, ssao_bias, ssao_direct_light_affect, ssao_ao_channel_affect, ssao_color, VS::EnvironmentSSAOQuality(ssao_quality), VS::EnvironmentSSAOBlur(ssao_blur), ssao_edge_sharpness);
}
float Environment::get_ssao_edge_sharpness() const {
@@ -1008,6 +1018,9 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ssao_direct_light_affect", "amount"), &Environment::set_ssao_direct_light_affect);
ClassDB::bind_method(D_METHOD("get_ssao_direct_light_affect"), &Environment::get_ssao_direct_light_affect);
+ ClassDB::bind_method(D_METHOD("set_ssao_ao_channel_affect", "amount"), &Environment::set_ssao_ao_channel_affect);
+ ClassDB::bind_method(D_METHOD("get_ssao_ao_channel_affect"), &Environment::get_ssao_ao_channel_affect);
+
ClassDB::bind_method(D_METHOD("set_ssao_color", "color"), &Environment::set_ssao_color);
ClassDB::bind_method(D_METHOD("get_ssao_color"), &Environment::get_ssao_color);
@@ -1028,6 +1041,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_intensity2", PROPERTY_HINT_RANGE, "0.0,128,0.1"), "set_ssao_intensity2", "get_ssao_intensity2");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_bias", PROPERTY_HINT_RANGE, "0.001,8,0.001"), "set_ssao_bias", "get_ssao_bias");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_light_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_direct_light_affect", "get_ssao_direct_light_affect");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "ssao_ao_channel_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_ao_channel_affect", "get_ssao_ao_channel_affect");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ssao_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ssao_color", "get_ssao_color");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_ssao_quality", "get_ssao_quality");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ssao_blur", PROPERTY_HINT_ENUM, "Disabled,1x1,2x2,3x3"), "set_ssao_blur", "get_ssao_blur");
@@ -1220,6 +1234,7 @@ Environment::Environment() {
ssao_intensity2 = 1;
ssao_bias = 0.01;
ssao_direct_light_affect = 0.0;
+ ssao_ao_channel_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 27fd57aa09..7d66c7e60b 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -127,6 +127,7 @@ private:
float ssao_intensity2;
float ssao_bias;
float ssao_direct_light_affect;
+ float ssao_ao_channel_affect;
Color ssao_color;
SSAOBlur ssao_blur;
float ssao_edge_sharpness;
@@ -274,6 +275,9 @@ public:
void set_ssao_direct_light_affect(float p_direct_light_affect);
float get_ssao_direct_light_affect() const;
+ void set_ssao_ao_channel_affect(float p_ao_channel_affect);
+ float get_ssao_ao_channel_affect() const;
+
void set_ssao_color(const Color &p_color);
Color get_ssao_color() const;
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 0bae9d9b2d..3dfde01320 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -386,7 +386,7 @@ Vector<CharType> BitmapFont::get_char_keys() const {
int count = 0;
while ((ct = char_map.next(ct))) {
- chars[count++] = *ct;
+ chars.write[count++] = *ct;
};
return chars;
@@ -438,7 +438,7 @@ Vector<BitmapFont::KerningPairKey> BitmapFont::get_kerning_pair_keys() const {
int i = 0;
for (Map<KerningPairKey, int>::Element *E = kerning_map.front(); E; E = E->next()) {
- ret[i++] = E->key();
+ ret.write[i++] = E->key();
}
return ret;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 5e7569586a..4727526b68 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -34,6 +34,8 @@
void Material::set_next_pass(const Ref<Material> &p_pass) {
+ ERR_FAIL_COND(p_pass == this);
+
if (next_pass == p_pass)
return;
@@ -145,11 +147,17 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
+ if (shader.is_valid()) {
+ shader->disconnect("changed", this, "_shader_changed");
+ }
+
shader = p_shader;
RID rid;
- if (shader.is_valid())
+ if (shader.is_valid()) {
rid = shader->get_rid();
+ shader->connect("changed", this, "_shader_changed");
+ }
VS::get_singleton()->material_set_shader(_get_material(), rid);
_change_notify(); //properties for shader exposed
@@ -171,12 +179,17 @@ Variant ShaderMaterial::get_shader_param(const StringName &p_param) const {
return VS::get_singleton()->material_get_param(_get_material(), p_param);
}
+void ShaderMaterial::_shader_changed() {
+ _change_notify(); //update all properties
+}
+
void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader);
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);
+ ClassDB::bind_method(D_METHOD("_shader_changed"), &ShaderMaterial::_shader_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader");
}
@@ -387,12 +400,20 @@ void SpatialMaterial::_update_shader() {
if (flags[FLAG_USE_VERTEX_LIGHTING]) {
code += ",vertex_lighting";
}
+ bool using_world = false;
if (flags[FLAG_TRIPLANAR_USE_WORLD] && (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR])) {
code += ",world_vertex_coords";
+ using_world = true;
}
if (flags[FLAG_DONT_RECEIVE_SHADOWS]) {
code += ",shadows_disabled";
}
+ if (flags[FLAG_DISABLE_AMBIENT_LIGHT]) {
+ code += ",ambient_light_disabled";
+ }
+ if (flags[FLAG_ENSURE_CORRECT_NORMALS]) {
+ code += ",ensure_correct_normals";
+ }
code += ";\n";
code += "uniform vec4 albedo : hint_color;\n";
@@ -406,7 +427,7 @@ void SpatialMaterial::_update_shader() {
if (proximity_fade_enabled) {
code += "uniform float proximity_fade_distance;\n";
}
- if (distance_fade_enabled) {
+ if (distance_fade != DISTANCE_FADE_DISABLED) {
code += "uniform float distance_fade_min;\n";
code += "uniform float distance_fade_max;\n";
}
@@ -537,9 +558,20 @@ void SpatialMaterial::_update_shader() {
case BILLBOARD_ENABLED: {
code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);\n";
+
+ if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
+ code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n";
+ }
} break;
case BILLBOARD_FIXED_Y: {
+
code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)),0.0),WORLD_MATRIX[3]);\n";
+
+ if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
+ code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,1,0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n";
+ } else {
+ code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1,0,0,0),vec4(0,1.0/length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n";
+ }
} break;
case BILLBOARD_PARTICLES: {
@@ -556,8 +588,6 @@ void SpatialMaterial::_update_shader() {
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";
- //handle rotation
- // code += "\tmat4 rotation = mat4("
} break;
}
@@ -756,7 +786,7 @@ void SpatialMaterial::_update_shader() {
code += "\tALBEDO *= 1.0 - ref_amount;\n";
code += "\tALPHA = 1.0;\n";
- } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || distance_fade_enabled || proximity_fade_enabled) {
+ } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) {
code += "\tALPHA = albedo.a * albedo_tex.a;\n";
}
@@ -767,8 +797,47 @@ void SpatialMaterial::_update_shader() {
code += "\tALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n";
}
- if (distance_fade_enabled) {
- code += "\tALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n";
+ if (distance_fade != DISTANCE_FADE_DISABLED) {
+ if (distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER) {
+
+ code += "\t{\n";
+ if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
+ code += "\t\tfloat fade_distance = abs((INV_CAMERA_MATRIX * WORLD_MATRIX[3]).z);\n";
+
+ } else {
+ code += "\t\tfloat fade_distance=-VERTEX.z;\n";
+ }
+
+ code += "\t\tfloat fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n";
+ code += "\t\tint x = int(FRAGCOORD.x) % 4;\n";
+ code += "\t\tint y = int(FRAGCOORD.y) % 4;\n";
+ code += "\t\tint index = x + y * 4;\n";
+ code += "\t\tfloat limit = 0.0;\n\n";
+ code += "\t\tif (x < 8) {\n";
+ code += "\t\t\tif (index == 0) limit = 0.0625;\n";
+ code += "\t\t\tif (index == 1) limit = 0.5625;\n";
+ code += "\t\t\tif (index == 2) limit = 0.1875;\n";
+ code += "\t\t\tif (index == 3) limit = 0.6875;\n";
+ code += "\t\t\tif (index == 4) limit = 0.8125;\n";
+ code += "\t\t\tif (index == 5) limit = 0.3125;\n";
+ code += "\t\t\tif (index == 6) limit = 0.9375;\n";
+ code += "\t\t\tif (index == 7) limit = 0.4375;\n";
+ code += "\t\t\tif (index == 8) limit = 0.25;\n";
+ code += "\t\t\tif (index == 9) limit = 0.75;\n";
+ code += "\t\t\tif (index == 10) limit = 0.125;\n";
+ code += "\t\t\tif (index == 11) limit = 0.625;\n";
+ code += "\t\t\tif (index == 12) limit = 1.0;\n";
+ code += "\t\t\tif (index == 13) limit = 0.5;\n";
+ code += "\t\t\tif (index == 14) limit = 0.875;\n";
+ code += "\t\t\tif (index == 15) limit = 0.375;\n";
+ code += "\t\t}\n\n";
+ code += "\tif (fade < limit)\n";
+ code += "\t\tdiscard;\n";
+ code += "\t}\n\n";
+
+ } else {
+ code += "\tALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n";
+ }
}
if (features[FEATURE_RIM]) {
@@ -855,7 +924,7 @@ void SpatialMaterial::_update_shader() {
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tvec4 detail_mask_tex = triplanar_texture(texture_detail_mask,uv1_power_normal);\n";
+ code += "\tvec4 detail_mask_tex = triplanar_texture(texture_detail_mask,uv1_power_normal,uv1_triplanar_pos);\n";
} else {
code += "\tvec4 detail_mask_tex = texture(texture_detail_mask,base_uv);\n";
}
@@ -1298,7 +1367,7 @@ void SpatialMaterial::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && !distance_fade_enabled) {
+ if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
property.usage = 0;
}
@@ -1619,15 +1688,15 @@ float SpatialMaterial::get_proximity_fade_distance() const {
return proximity_fade_distance;
}
-void SpatialMaterial::set_distance_fade(bool p_enable) {
+void SpatialMaterial::set_distance_fade(DistanceFadeMode p_mode) {
- distance_fade_enabled = p_enable;
+ distance_fade = p_mode;
_queue_shader_change();
_change_notify();
}
-bool SpatialMaterial::is_distance_fade_enabled() const {
+SpatialMaterial::DistanceFadeMode SpatialMaterial::get_distance_fade() const {
- return distance_fade_enabled;
+ return distance_fade;
}
void SpatialMaterial::set_distance_fade_max_distance(float p_distance) {
@@ -1833,8 +1902,8 @@ void SpatialMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &SpatialMaterial::set_proximity_fade_distance);
ClassDB::bind_method(D_METHOD("get_proximity_fade_distance"), &SpatialMaterial::get_proximity_fade_distance);
- ClassDB::bind_method(D_METHOD("set_distance_fade", "enabled"), &SpatialMaterial::set_distance_fade);
- ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &SpatialMaterial::is_distance_fade_enabled);
+ ClassDB::bind_method(D_METHOD("set_distance_fade", "mode"), &SpatialMaterial::set_distance_fade);
+ ClassDB::bind_method(D_METHOD("get_distance_fade"), &SpatialMaterial::get_distance_fade);
ClassDB::bind_method(D_METHOD("set_distance_fade_max_distance", "distance"), &SpatialMaterial::set_distance_fade_max_distance);
ClassDB::bind_method(D_METHOD("get_distance_fade_max_distance"), &SpatialMaterial::get_distance_fade_max_distance);
@@ -1852,6 +1921,8 @@ void SpatialMaterial::_bind_methods() {
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_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_ensure_correct_normals"), "set_flag", "get_flag", FLAG_ENSURE_CORRECT_NORMALS);
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);
@@ -1865,6 +1936,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_line_width", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_line_width", "get_line_width");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "params_billboard_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particle Billboard"), "set_billboard_mode", "get_billboard_mode");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_billboard_keep_scale"), "set_flag", "get_flag", FLAG_BILLBOARD_KEEP_SCALE);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "params_grow"), "set_grow_enabled", "is_grow_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_grow_amount", PROPERTY_HINT_RANGE, "-16,10,0.01"), "set_grow", "get_grow");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_use_alpha_scissor"), "set_flag", "get_flag", FLAG_USE_ALPHA_SCISSOR);
@@ -1974,7 +2046,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("Distance Fade", "distance_fade_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enable"), "set_distance_fade", "is_distance_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "distance_fade_mode", PROPERTY_HINT_ENUM, "Disabled,PixelAlpha,PixelDither,ObjectDither"), "set_distance_fade", "get_distance_fade");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
@@ -2034,6 +2106,7 @@ void SpatialMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_SRGB_VERTEX_COLOR);
BIND_ENUM_CONSTANT(FLAG_USE_POINT_SIZE);
BIND_ENUM_CONSTANT(FLAG_FIXED_SIZE);
+ BIND_ENUM_CONSTANT(FLAG_BILLBOARD_KEEP_SCALE);
BIND_ENUM_CONSTANT(FLAG_UV1_USE_TRIPLANAR);
BIND_ENUM_CONSTANT(FLAG_UV2_USE_TRIPLANAR);
BIND_ENUM_CONSTANT(FLAG_AO_ON_UV2);
@@ -2042,6 +2115,8 @@ void SpatialMaterial::_bind_methods() {
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_DISABLE_AMBIENT_LIGHT);
+ BIND_ENUM_CONSTANT(FLAG_ENSURE_CORRECT_NORMALS);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
@@ -2069,15 +2144,20 @@ void SpatialMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_OP_ADD);
BIND_ENUM_CONSTANT(EMISSION_OP_MULTIPLY);
+
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_DISABLED);
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_ALPHA);
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_DITHER);
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_OBJECT_DITHER);
}
SpatialMaterial::SpatialMaterial() :
element(this) {
- //initialize to right values
+ // Initialize to the same values as the shader
set_albedo(Color(1.0, 1.0, 1.0, 1.0));
set_specular(0.5);
- set_roughness(0.0);
+ set_roughness(1.0);
set_metallic(0.0);
set_emission(Color(0, 0, 0));
set_emission_energy(1.0);
@@ -2107,7 +2187,7 @@ SpatialMaterial::SpatialMaterial() :
emission_op = EMISSION_OP_ADD;
proximity_fade_enabled = false;
- distance_fade_enabled = false;
+ distance_fade = DISTANCE_FADE_DISABLED;
set_proximity_fade_distance(1);
set_distance_fade_min_distance(0);
set_distance_fade_max_distance(10);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index ce733bfb8d..f43d240a53 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -92,6 +92,8 @@ protected:
virtual bool _can_do_next_pass() const;
+ void _shader_changed();
+
public:
void set_shader(const Ref<Shader> &p_shader);
Ref<Shader> get_shader() const;
@@ -181,6 +183,7 @@ public:
FLAG_SRGB_VERTEX_COLOR,
FLAG_USE_POINT_SIZE,
FLAG_FIXED_SIZE,
+ FLAG_BILLBOARD_KEEP_SCALE,
FLAG_UV1_USE_TRIPLANAR,
FLAG_UV2_USE_TRIPLANAR,
FLAG_TRIPLANAR_USE_WORLD,
@@ -189,6 +192,8 @@ public:
FLAG_USE_ALPHA_SCISSOR,
FLAG_ALBEDO_TEXTURE_FORCE_SRGB,
FLAG_DONT_RECEIVE_SHADOWS,
+ FLAG_ENSURE_CORRECT_NORMALS,
+ FLAG_DISABLE_AMBIENT_LIGHT,
FLAG_MAX
};
@@ -228,6 +233,13 @@ public:
EMISSION_OP_MULTIPLY
};
+ enum DistanceFadeMode {
+ DISTANCE_FADE_DISABLED,
+ DISTANCE_FADE_PIXEL_ALPHA,
+ DISTANCE_FADE_PIXEL_DITHER,
+ DISTANCE_FADE_OBJECT_DITHER,
+ };
+
private:
union MaterialKey {
@@ -237,7 +249,7 @@ private:
uint64_t blend_mode : 2;
uint64_t depth_draw_mode : 2;
uint64_t cull_mode : 2;
- uint64_t flags : 15;
+ uint64_t flags : 18;
uint64_t detail_blend_mode : 2;
uint64_t diffuse_mode : 3;
uint64_t specular_mode : 2;
@@ -246,7 +258,7 @@ private:
uint64_t billboard_mode : 2;
uint64_t grow : 1;
uint64_t proximity_fade : 1;
- uint64_t distance_fade : 1;
+ uint64_t distance_fade : 2;
uint64_t emission_op : 1;
};
@@ -291,7 +303,7 @@ private:
mk.deep_parallax = deep_parallax ? 1 : 0;
mk.grow = grow_enabled;
mk.proximity_fade = proximity_fade_enabled;
- mk.distance_fade = distance_fade_enabled;
+ mk.distance_fade = distance_fade;
mk.emission_op = emission_op;
return mk;
@@ -397,7 +409,7 @@ private:
bool proximity_fade_enabled;
float proximity_fade_distance;
- bool distance_fade_enabled;
+ DistanceFadeMode distance_fade;
float distance_fade_max_distance;
float distance_fade_min_distance;
@@ -578,8 +590,8 @@ public:
void set_proximity_fade_distance(float p_distance);
float get_proximity_fade_distance() const;
- void set_distance_fade(bool p_enable);
- bool is_distance_fade_enabled() const;
+ void set_distance_fade(DistanceFadeMode p_mode);
+ DistanceFadeMode get_distance_fade() const;
void set_distance_fade_max_distance(float p_distance);
float get_distance_fade_max_distance() const;
@@ -625,6 +637,7 @@ VARIANT_ENUM_CAST(SpatialMaterial::SpecularMode)
VARIANT_ENUM_CAST(SpatialMaterial::BillboardMode)
VARIANT_ENUM_CAST(SpatialMaterial::TextureChannel)
VARIANT_ENUM_CAST(SpatialMaterial::EmissionOperator)
+VARIANT_ENUM_CAST(SpatialMaterial::DistanceFadeMode)
//////////////////////
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index b0620d3363..e6ef956dc5 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -40,7 +40,6 @@
void Mesh::_clear_triangle_mesh() const {
triangle_mesh.unref();
- ;
}
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
@@ -110,6 +109,54 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
return triangle_mesh;
}
+void Mesh::generate_debug_mesh_lines(Vector<Vector3> &r_lines) {
+
+ Ref<TriangleMesh> tm = generate_triangle_mesh();
+ if (tm.is_null())
+ return;
+
+ PoolVector<int> triangle_indices;
+ tm->get_indices(&triangle_indices);
+ const int triangles_num = tm->get_triangles().size();
+ PoolVector<Vector3> vertices = tm->get_vertices();
+
+ r_lines.resize(tm->get_triangles().size() * 6); // 3 lines x 2 points each line
+
+ PoolVector<int>::Read ind_r = triangle_indices.read();
+ PoolVector<Vector3>::Read ver_r = vertices.read();
+ for (int j = 0, x = 0, i = 0; i < triangles_num; j += 6, x += 3, ++i) {
+ // Triangle line 1
+ r_lines.write[j + 0] = ver_r[ind_r[x + 0]];
+ r_lines.write[j + 1] = ver_r[ind_r[x + 1]];
+
+ // Triangle line 2
+ r_lines.write[j + 2] = ver_r[ind_r[x + 1]];
+ r_lines.write[j + 3] = ver_r[ind_r[x + 2]];
+
+ // Triangle line 3
+ r_lines.write[j + 4] = ver_r[ind_r[x + 2]];
+ r_lines.write[j + 5] = ver_r[ind_r[x + 0]];
+ }
+}
+void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) {
+ Ref<TriangleMesh> tm = generate_triangle_mesh();
+ if (tm.is_null())
+ return;
+
+ PoolVector<Vector3> vertices = tm->get_vertices();
+
+ int vertices_size = vertices.size();
+ r_points.resize(vertices_size);
+ for (int i = 0; i < vertices_size; ++i) {
+ r_points.write[i] = vertices[i];
+ }
+}
+
+bool Mesh::surface_is_softbody_friendly(int p_idx) const {
+ const uint32_t surface_format = surface_get_format(p_idx);
+ return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_VERTEX)) && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL)));
+}
+
PoolVector<Face3> Mesh::get_faces() const {
Ref<TriangleMesh> tm = generate_triangle_mesh();
@@ -435,6 +482,11 @@ void Mesh::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint");
+ ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count);
+ ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays);
+ ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays);
+ ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &Mesh::surface_get_material);
+
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
BIND_ENUM_CONSTANT(PRIMITIVE_LINES);
BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP);
@@ -484,6 +536,10 @@ void Mesh::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_MAX);
}
+void Mesh::clear_cache() {
+ _clear_triangle_mesh();
+}
+
Mesh::Mesh() {
}
@@ -616,7 +672,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
bone_aabb.resize(baabb.size());
for (int i = 0; i < baabb.size(); i++) {
- bone_aabb[i] = baabb[i];
+ bone_aabb.write[i] = baabb[i];
}
}
@@ -788,8 +844,8 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &
aabb.expand_to(vtx[i]);
}
- surfaces[surfaces.size() - 1].aabb = aabb;
- surfaces[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY;
+ surfaces.write[surfaces.size() - 1].aabb = aabb;
+ surfaces.write[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY;
_recompute_aabb();
}
@@ -908,18 +964,28 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material)
ERR_FAIL_INDEX(p_idx, surfaces.size());
if (surfaces[p_idx].material == p_material)
return;
- surfaces[p_idx].material = p_material;
+ surfaces.write[p_idx].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();
}
+int ArrayMesh::surface_find_by_name(const String &p_name) const {
+ for (int i = 0; i < surfaces.size(); i++) {
+ if (surfaces[i].name == p_name) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
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;
+ surfaces.write[p_idx].name = p_name;
emit_changed();
}
@@ -939,7 +1005,7 @@ void ArrayMesh::surface_update_region(int p_surface, int p_offset, const PoolVec
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;
+ surfaces.write[p_idx].aabb = p_aabb;
// set custom aabb too?
emit_changed();
}
@@ -1042,8 +1108,8 @@ void ArrayMesh::regen_normalmaps() {
for (int i = 0; i < surfs.size(); i++) {
- surfs[i]->generate_tangents();
- surfs[i]->commit(Ref<ArrayMesh>(this));
+ surfs.write[i]->generate_tangents();
+ surfs.write[i]->commit(Ref<ArrayMesh>(this));
}
}
@@ -1108,13 +1174,13 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
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] = 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);
+ vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_index.write[j + vertex_ofs] = Pair<int, int>(i, j);
}
PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX];
@@ -1180,7 +1246,7 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
surfaces_tools.push_back(st); //stay there
}
- print_line("gen indices: " + itos(gen_index_count));
+ print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
@@ -1197,31 +1263,31 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second];
if (surfaces[surface].format & ARRAY_FORMAT_COLOR) {
- surfaces_tools[surface]->add_color(v.color);
+ surfaces_tools.write[surface]->add_color(v.color);
}
if (surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
- surfaces_tools[surface]->add_uv(v.uv);
+ surfaces_tools.write[surface]->add_uv(v.uv);
}
if (surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
- surfaces_tools[surface]->add_normal(v.normal);
+ surfaces_tools.write[surface]->add_normal(v.normal);
}
if (surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
- surfaces_tools[surface]->add_tangent(t);
+ surfaces_tools.write[surface]->add_tangent(t);
}
if (surfaces[surface].format & ARRAY_FORMAT_BONES) {
- surfaces_tools[surface]->add_bones(v.bones);
+ surfaces_tools.write[surface]->add_bones(v.bones);
}
if (surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
- surfaces_tools[surface]->add_weights(v.weights);
+ surfaces_tools.write[surface]->add_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
- surfaces_tools[surface]->add_uv2(uv2);
+ surfaces_tools.write[surface]->add_uv2(uv2);
- surfaces_tools[surface]->add_vertex(v.vertex);
+ surfaces_tools.write[surface]->add_vertex(v.vertex);
}
}
@@ -1233,8 +1299,8 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
//generate surfaces
for (int i = 0; i < surfaces_tools.size(); i++) {
- surfaces_tools[i]->index();
- surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format);
+ surfaces_tools.write[i]->index();
+ surfaces_tools.write[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format);
}
set_lightmap_size_hint(Size2(size_x, size_y));
@@ -1252,7 +1318,6 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode);
ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT));
- ClassDB::bind_method(D_METHOD("get_surface_count"), &ArrayMesh::get_surface_count);
ClassDB::bind_method(D_METHOD("surface_remove", "surf_idx"), &ArrayMesh::surface_remove);
ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region);
ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len);
@@ -1260,11 +1325,9 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format);
ClassDB::bind_method(D_METHOD("surface_get_primitive_type", "surf_idx"), &ArrayMesh::surface_get_primitive_type);
ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &ArrayMesh::surface_set_material);
- ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &ArrayMesh::surface_get_material);
+ ClassDB::bind_method(D_METHOD("surface_find_by_name", "name"), &ArrayMesh::surface_find_by_name);
ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name);
ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name);
- ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &ArrayMesh::surface_get_arrays);
- ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &ArrayMesh::surface_get_blend_shape_arrays);
ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape);
ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape);
ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline);
@@ -1272,7 +1335,7 @@ 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::bind_method(D_METHOD("lightmap_unwrap", "transform", "texel_size"), &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);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index e8b7ecaf9a..36bfca49f8 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -100,7 +100,7 @@ public:
ARRAY_FLAG_USE_16_BIT_BONES = ARRAY_COMPRESS_INDEX << 2,
ARRAY_FLAG_USE_DYNAMIC_UPDATE = ARRAY_COMPRESS_INDEX << 3,
- ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_VERTEX | ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS
+ ARRAY_COMPRESS_DEFAULT = ARRAY_COMPRESS_NORMAL | ARRAY_COMPRESS_TANGENT | ARRAY_COMPRESS_COLOR | ARRAY_COMPRESS_TEX_UV | ARRAY_COMPRESS_TEX_UV2 | ARRAY_COMPRESS_WEIGHTS
};
@@ -123,6 +123,7 @@ public:
virtual int get_surface_count() const = 0;
virtual int surface_get_array_len(int p_idx) const = 0;
virtual int surface_get_array_index_len(int p_idx) const = 0;
+ virtual bool surface_is_softbody_friendly(int p_idx) const;
virtual Array surface_get_arrays(int p_surface) const = 0;
virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0;
virtual uint32_t surface_get_format(int p_idx) const = 0;
@@ -133,6 +134,8 @@ public:
PoolVector<Face3> get_faces() const;
Ref<TriangleMesh> generate_triangle_mesh() const;
+ void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
+ void generate_debug_mesh_indices(Vector<Vector3> &r_points);
Ref<Shape> create_trimesh_shape() const;
Ref<Shape> create_convex_shape() const;
@@ -143,6 +146,7 @@ public:
void set_lightmap_size_hint(const Vector2 &p_size);
Size2 get_lightmap_size_hint() const;
+ void clear_cache();
Mesh();
};
@@ -208,6 +212,7 @@ public:
void surface_set_material(int p_idx, const Ref<Material> &p_material);
Ref<Material> surface_get_material(int p_idx) const;
+ int surface_find_by_name(const String &p_name) const;
void surface_set_name(int p_idx, const String &p_name);
String surface_get_name(int p_idx) const;
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 8639b325c3..6732303925 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -120,7 +120,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
v.bones.push_back(bo[i * 4 + 3]);
}
- vertices[i] = v;
+ vertices.write[i] = v;
}
PoolVector<int> indices;
@@ -143,7 +143,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
for (int i = 0; i < icount; i += 3) {
- Vertex *v[3] = { &vertices[r[i + 0]], &vertices[r[i + 1]], &vertices[r[i + 2]] };
+ Vertex *v[3] = { &vertices.write[r[i + 0]], &vertices.write[r[i + 1]], &vertices.write[r[i + 2]] };
int fidx = faces.size();
Face face;
@@ -169,7 +169,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf
edges.push_back(e);
}
- edges[face.edges[j]].faces.push_back(fidx);
+ edges.write[face.edges[j]].faces.push_back(fidx);
v[j]->faces.push_back(fidx);
v[j]->edges.push_back(face.edges[j]);
}
@@ -247,7 +247,7 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) {
for (int i = 0; i < vcount; i++) {
- Vertex &vtx = vertices[i];
+ const Vertex &vtx = vertices[i];
vr[i] = vtx.vertex;
if (nr.ptr())
@@ -344,7 +344,7 @@ Vector3 MeshDataTool::get_vertex(int p_idx) const {
void MeshDataTool::set_vertex(int p_idx, const Vector3 &p_vertex) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].vertex = p_vertex;
+ vertices.write[p_idx].vertex = p_vertex;
}
Vector3 MeshDataTool::get_vertex_normal(int p_idx) const {
@@ -355,7 +355,7 @@ Vector3 MeshDataTool::get_vertex_normal(int p_idx) const {
void MeshDataTool::set_vertex_normal(int p_idx, const Vector3 &p_normal) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].normal = p_normal;
+ vertices.write[p_idx].normal = p_normal;
format |= Mesh::ARRAY_FORMAT_NORMAL;
}
@@ -367,7 +367,7 @@ Plane MeshDataTool::get_vertex_tangent(int p_idx) const {
void MeshDataTool::set_vertex_tangent(int p_idx, const Plane &p_tangent) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].tangent = p_tangent;
+ vertices.write[p_idx].tangent = p_tangent;
format |= Mesh::ARRAY_FORMAT_TANGENT;
}
@@ -379,7 +379,7 @@ Vector2 MeshDataTool::get_vertex_uv(int p_idx) const {
void MeshDataTool::set_vertex_uv(int p_idx, const Vector2 &p_uv) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].uv = p_uv;
+ vertices.write[p_idx].uv = p_uv;
format |= Mesh::ARRAY_FORMAT_TEX_UV;
}
@@ -391,7 +391,7 @@ Vector2 MeshDataTool::get_vertex_uv2(int p_idx) const {
void MeshDataTool::set_vertex_uv2(int p_idx, const Vector2 &p_uv2) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].uv2 = p_uv2;
+ vertices.write[p_idx].uv2 = p_uv2;
format |= Mesh::ARRAY_FORMAT_TEX_UV2;
}
@@ -403,7 +403,7 @@ Color MeshDataTool::get_vertex_color(int p_idx) const {
void MeshDataTool::set_vertex_color(int p_idx, const Color &p_color) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].color = p_color;
+ vertices.write[p_idx].color = p_color;
format |= Mesh::ARRAY_FORMAT_COLOR;
}
@@ -415,7 +415,7 @@ Vector<int> MeshDataTool::get_vertex_bones(int p_idx) const {
void MeshDataTool::set_vertex_bones(int p_idx, const Vector<int> &p_bones) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].bones = p_bones;
+ vertices.write[p_idx].bones = p_bones;
format |= Mesh::ARRAY_FORMAT_BONES;
}
@@ -426,7 +426,7 @@ Vector<float> MeshDataTool::get_vertex_weights(int p_idx) const {
}
void MeshDataTool::set_vertex_weights(int p_idx, const Vector<float> &p_weights) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].weights = p_weights;
+ vertices.write[p_idx].weights = p_weights;
format |= Mesh::ARRAY_FORMAT_WEIGHTS;
}
@@ -439,7 +439,7 @@ Variant MeshDataTool::get_vertex_meta(int p_idx) const {
void MeshDataTool::set_vertex_meta(int p_idx, const Variant &p_meta) {
ERR_FAIL_INDEX(p_idx, vertices.size());
- vertices[p_idx].meta = p_meta;
+ vertices.write[p_idx].meta = p_meta;
}
Vector<int> MeshDataTool::get_vertex_edges(int p_idx) const {
@@ -472,7 +472,7 @@ Variant MeshDataTool::get_edge_meta(int p_idx) const {
void MeshDataTool::set_edge_meta(int p_idx, const Variant &p_meta) {
ERR_FAIL_INDEX(p_idx, edges.size());
- edges[p_idx].meta = p_meta;
+ edges.write[p_idx].meta = p_meta;
}
int MeshDataTool::get_face_vertex(int p_face, int p_vertex) const {
@@ -495,7 +495,7 @@ Variant MeshDataTool::get_face_meta(int p_face) const {
void MeshDataTool::set_face_meta(int p_face, const Variant &p_meta) {
ERR_FAIL_INDEX(p_face, faces.size());
- faces[p_face].meta = p_meta;
+ faces.write[p_face].meta = p_meta;
}
Vector3 MeshDataTool::get_face_normal(int p_face) const {
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index e1d3540fd1..a1d3e0ba1e 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -209,7 +209,7 @@ Vector<int> MeshLibrary::get_item_list() const {
int idx = 0;
for (Map<int, Item>::Element *E = item_map.front(); E; E = E->next()) {
- ret[idx++] = E->key();
+ ret.write[idx++] = E->key();
}
return ret;
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 846f6e356e..f034e07ff9 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -31,6 +31,7 @@
#include "packed_scene.h"
#include "core/core_string_names.h"
+#include "engine.h"
#include "io/resource_loader.h"
#include "project_settings.h"
#include "scene/2d/node_2d.h"
@@ -105,7 +106,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (i == 0 && base_scene_idx >= 0) {
//scene inheritance on root node
- //print_line("scene inherit");
Ref<PackedScene> sdata = props[base_scene_idx];
ERR_FAIL_COND_V(!sdata.is_valid(), NULL);
node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); //only main gets main edit state
@@ -116,7 +116,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
} else if (n.instance >= 0) {
//instance a scene into this node
- //print_line("instance");
if (n.instance & FLAG_INSTANCE_IS_PLACEHOLDER) {
String path = props[n.instance & FLAG_MASK];
@@ -140,7 +139,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
} else if (n.type == TYPE_INSTANCED) {
- //print_line("instanced");
//get the node from somewhere, it likely already exists from another instance
if (parent) {
node = parent->_get_child_by_name(snames[n.name]);
@@ -151,7 +149,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
#endif
}
} else if (ClassDB::is_class_enabled(snames[n.type])) {
- //print_line("created");
//node belongs to this scene and must be created
Object *obj = ClassDB::instance(snames[n.type]);
if (!Object::cast_to<Node>(obj)) {
@@ -279,7 +276,12 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
stray_instances.push_back(node); //can't be added, go to stray list
}
} else {
- node->_set_name_nocheck(snames[n.name]);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ //validate name if using editor, to avoid broken
+ node->set_name(snames[n.name]);
+ } else {
+ node->_set_name_nocheck(snames[n.name]);
+ }
}
}
@@ -325,7 +327,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (c.binds.size()) {
binds.resize(c.binds.size());
for (int j = 0; j < c.binds.size(); j++)
- binds[j] = props[c.binds[j]];
+ binds.write[j] = props[c.binds[j]];
}
cfrom->connect(snames[c.signal], cto, snames[c.method], binds, CONNECT_PERSIST | c.flags);
@@ -389,7 +391,15 @@ 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();
+
+ //really convoluted condition, but it basically checks that index is only saved when part of an inherited scene OR the node parent is from the edited scene
+ if (p_owner->get_scene_inherited_state().is_null() && (p_node == p_owner || (p_node->get_owner() == p_owner && (p_node->get_parent() == p_owner || p_node->get_parent()->get_owner() == p_owner)))) {
+ //do not save index, because it belongs to saved scene and scene is not inherited
+ nd.index = -1;
+ } else {
+ //part of an inherited scene, or parent is from an instanced scene
+ 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.
@@ -477,15 +487,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
if (E->get().usage & PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE) {
isdefault = true; //is script default value
}
- /*
- if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) {
- continue;
- }
- */
-
- //print_line("PASSED!");
- //print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE));
- //print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one()));
if (pack_state_stack.size()) {
// we are on part of an instanced subscene
@@ -875,7 +876,7 @@ Error SceneState::pack(Node *p_scene) {
for (Map<StringName, int>::Element *E = name_map.front(); E; E = E->next()) {
- names[E->get()] = E->key();
+ names.write[E->get()] = E->key();
}
variants.resize(variant_map.size());
@@ -883,13 +884,13 @@ Error SceneState::pack(Node *p_scene) {
while ((K = variant_map.next(K))) {
int idx = variant_map[*K];
- variants[idx] = *K;
+ variants.write[idx] = *K;
}
node_paths.resize(nodepath_map.size());
for (Map<Node *, int>::Element *E = nodepath_map.front(); E; E = E->next()) {
- node_paths[E->get()] = scene->get_path_to(E->key());
+ node_paths.write[E->get()] = scene->get_path_to(E->key());
}
return OK;
@@ -1090,7 +1091,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
names.resize(namecount);
PoolVector<String>::Read r = snames.read();
for (int i = 0; i < names.size(); i++)
- names[i] = r[i];
+ names.write[i] = r[i];
}
Array svariants = p_dictionary["variants"];
@@ -1100,7 +1101,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
variants.resize(varcount);
for (int i = 0; i < varcount; i++) {
- variants[i] = svariants[i];
+ variants.write[i] = svariants[i];
}
} else {
@@ -1114,7 +1115,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
PoolVector<int>::Read r = snodes.read();
int idx = 0;
for (int i = 0; i < nc; i++) {
- NodeData &nd = nodes[i];
+ NodeData &nd = nodes.write[i];
nd.parent = r[idx++];
nd.owner = r[idx++];
nd.type = r[idx++];
@@ -1126,13 +1127,13 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
nd.properties.resize(r[idx++]);
for (int j = 0; j < nd.properties.size(); j++) {
- nd.properties[j].name = r[idx++];
- nd.properties[j].value = r[idx++];
+ nd.properties.write[j].name = r[idx++];
+ nd.properties.write[j].value = r[idx++];
}
nd.groups.resize(r[idx++]);
for (int j = 0; j < nd.groups.size(); j++) {
- nd.groups[j] = r[idx++];
+ nd.groups.write[j] = r[idx++];
}
}
}
@@ -1146,7 +1147,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
PoolVector<int>::Read r = sconns.read();
int idx = 0;
for (int i = 0; i < cc; i++) {
- ConnectionData &cd = connections[i];
+ ConnectionData &cd = connections.write[i];
cd.from = r[idx++];
cd.to = r[idx++];
cd.signal = r[idx++];
@@ -1156,7 +1157,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
for (int j = 0; j < cd.binds.size(); j++) {
- cd.binds[j] = r[idx++];
+ cd.binds.write[j] = r[idx++];
}
}
}
@@ -1167,7 +1168,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
}
node_paths.resize(np.size());
for (int i = 0; i < np.size(); i++) {
- node_paths[i] = np[i];
+ node_paths.write[i] = np[i];
}
Array ei;
@@ -1181,7 +1182,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
editable_instances.resize(ei.size());
for (int i = 0; i < editable_instances.size(); i++) {
- editable_instances[i] = ei[i];
+ editable_instances.write[i] = ei[i];
}
//path=p_dictionary["path"];
@@ -1563,13 +1564,13 @@ void SceneState::add_node_property(int p_node, int p_name, int p_value) {
NodeData::Property prop;
prop.name = p_name;
prop.value = p_value;
- nodes[p_node].properties.push_back(prop);
+ nodes.write[p_node].properties.push_back(prop);
}
void SceneState::add_node_group(int p_node, int p_group) {
ERR_FAIL_INDEX(p_node, nodes.size());
ERR_FAIL_INDEX(p_group, names.size());
- nodes[p_node].groups.push_back(p_group);
+ nodes.write[p_node].groups.push_back(p_group);
}
void SceneState::set_base_scene(int p_idx) {
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
new file mode 100644
index 0000000000..218a4cefe7
--- /dev/null
+++ b/scene/resources/particles_material.cpp
@@ -0,0 +1,1259 @@
+/*************************************************************************/
+/* particles_material.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 "particles_material.h"
+
+Mutex *ParticlesMaterial::material_mutex = NULL;
+SelfList<ParticlesMaterial>::List ParticlesMaterial::dirty_materials;
+Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map;
+ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = NULL;
+
+void ParticlesMaterial::init_shaders() {
+
+#ifndef NO_THREADS
+ material_mutex = Mutex::create();
+#endif
+
+ shader_names = memnew(ShaderNames);
+
+ shader_names->spread = "spread";
+ shader_names->flatness = "flatness";
+ shader_names->initial_linear_velocity = "initial_linear_velocity";
+ shader_names->initial_angle = "initial_angle";
+ shader_names->angular_velocity = "angular_velocity";
+ shader_names->orbit_velocity = "orbit_velocity";
+ shader_names->linear_accel = "linear_accel";
+ shader_names->radial_accel = "radial_accel";
+ shader_names->tangent_accel = "tangent_accel";
+ shader_names->damping = "damping";
+ shader_names->scale = "scale";
+ shader_names->hue_variation = "hue_variation";
+ shader_names->anim_speed = "anim_speed";
+ shader_names->anim_offset = "anim_offset";
+
+ shader_names->initial_linear_velocity_random = "initial_linear_velocity_random";
+ shader_names->initial_angle_random = "initial_angle_random";
+ shader_names->angular_velocity_random = "angular_velocity_random";
+ shader_names->orbit_velocity_random = "orbit_velocity_random";
+ shader_names->linear_accel_random = "linear_accel_random";
+ shader_names->radial_accel_random = "radial_accel_random";
+ shader_names->tangent_accel_random = "tangent_accel_random";
+ shader_names->damping_random = "damping_random";
+ shader_names->scale_random = "scale_random";
+ shader_names->hue_variation_random = "hue_variation_random";
+ shader_names->anim_speed_random = "anim_speed_random";
+ shader_names->anim_offset_random = "anim_offset_random";
+
+ shader_names->angle_texture = "angle_texture";
+ shader_names->angular_velocity_texture = "angular_velocity_texture";
+ shader_names->orbit_velocity_texture = "orbit_velocity_texture";
+ shader_names->linear_accel_texture = "linear_accel_texture";
+ shader_names->radial_accel_texture = "radial_accel_texture";
+ shader_names->tangent_accel_texture = "tangent_accel_texture";
+ shader_names->damping_texture = "damping_texture";
+ shader_names->scale_texture = "scale_texture";
+ shader_names->hue_variation_texture = "hue_variation_texture";
+ shader_names->anim_speed_texture = "anim_speed_texture";
+ shader_names->anim_offset_texture = "anim_offset_texture";
+
+ shader_names->color = "color_value";
+ shader_names->color_ramp = "color_ramp";
+
+ shader_names->emission_sphere_radius = "emission_sphere_radius";
+ shader_names->emission_box_extents = "emission_box_extents";
+ shader_names->emission_texture_point_count = "emission_texture_point_count";
+ shader_names->emission_texture_points = "emission_texture_points";
+ shader_names->emission_texture_normal = "emission_texture_normal";
+ shader_names->emission_texture_color = "emission_texture_color";
+
+ shader_names->trail_divisor = "trail_divisor";
+ shader_names->trail_size_modifier = "trail_size_modifier";
+ shader_names->trail_color_modifier = "trail_color_modifier";
+
+ shader_names->gravity = "gravity";
+}
+
+void ParticlesMaterial::finish_shaders() {
+
+#ifndef NO_THREADS
+ memdelete(material_mutex);
+#endif
+
+ memdelete(shader_names);
+}
+
+void ParticlesMaterial::_update_shader() {
+
+ dirty_materials.remove(&element);
+
+ MaterialKey mk = _compute_key();
+ if (mk.key == current_key.key)
+ return; //no update required in the end
+
+ 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);
+ }
+ }
+
+ current_key = mk;
+
+ if (shader_map.has(mk)) {
+
+ VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ shader_map[mk].users++;
+ return;
+ }
+
+ //must create a shader!
+
+ String code = "shader_type particles;\n";
+
+ code += "uniform float spread;\n";
+ code += "uniform float flatness;\n";
+ code += "uniform float initial_linear_velocity;\n";
+ code += "uniform float initial_angle;\n";
+ code += "uniform float angular_velocity;\n";
+ code += "uniform float orbit_velocity;\n";
+ code += "uniform float linear_accel;\n";
+ code += "uniform float radial_accel;\n";
+ code += "uniform float tangent_accel;\n";
+ code += "uniform float damping;\n";
+ code += "uniform float scale;\n";
+ code += "uniform float hue_variation;\n";
+ code += "uniform float anim_speed;\n";
+ code += "uniform float anim_offset;\n";
+
+ code += "uniform float initial_linear_velocity_random;\n";
+ code += "uniform float initial_angle_random;\n";
+ code += "uniform float angular_velocity_random;\n";
+ code += "uniform float orbit_velocity_random;\n";
+ code += "uniform float linear_accel_random;\n";
+ code += "uniform float radial_accel_random;\n";
+ code += "uniform float tangent_accel_random;\n";
+ code += "uniform float damping_random;\n";
+ code += "uniform float scale_random;\n";
+ code += "uniform float hue_variation_random;\n";
+ code += "uniform float anim_speed_random;\n";
+ code += "uniform float anim_offset_random;\n";
+
+ switch (emission_shape) {
+ case EMISSION_SHAPE_POINT: {
+ //do none
+ } break;
+ case EMISSION_SHAPE_SPHERE: {
+ code += "uniform float emission_sphere_radius;\n";
+ } break;
+ case EMISSION_SHAPE_BOX: {
+ code += "uniform vec3 emission_box_extents;\n";
+ } break;
+ case EMISSION_SHAPE_DIRECTED_POINTS: {
+ code += "uniform sampler2D emission_texture_normal : hint_black;\n";
+ } //fallthrough
+ case EMISSION_SHAPE_POINTS: {
+ code += "uniform sampler2D emission_texture_points : hint_black;\n";
+ code += "uniform int emission_texture_point_count;\n";
+ if (emission_color_texture.is_valid()) {
+ code += "uniform sampler2D emission_texture_color : hint_white;\n";
+ }
+ } break;
+ }
+
+ code += "uniform vec4 color_value : hint_color;\n";
+
+ code += "uniform int trail_divisor;\n";
+
+ code += "uniform vec3 gravity;\n";
+
+ if (color_ramp.is_valid())
+ code += "uniform sampler2D color_ramp;\n";
+
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+ code += "uniform sampler2D linear_velocity_texture;\n";
+ if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
+ code += "uniform sampler2D orbit_velocity_texture;\n";
+ if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
+ code += "uniform sampler2D angular_velocity_texture;\n";
+ if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
+ code += "uniform sampler2D linear_accel_texture;\n";
+ if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
+ code += "uniform sampler2D radial_accel_texture;\n";
+ if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
+ code += "uniform sampler2D tangent_accel_texture;\n";
+ if (tex_parameters[PARAM_DAMPING].is_valid())
+ code += "uniform sampler2D damping_texture;\n";
+ if (tex_parameters[PARAM_ANGLE].is_valid())
+ code += "uniform sampler2D angle_texture;\n";
+ if (tex_parameters[PARAM_SCALE].is_valid())
+ code += "uniform sampler2D scale_texture;\n";
+ if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
+ code += "uniform sampler2D hue_variation_texture;\n";
+ if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
+ code += "uniform sampler2D anim_speed_texture;\n";
+ if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
+ code += "uniform sampler2D anim_offset_texture;\n";
+
+ if (trail_size_modifier.is_valid()) {
+ code += "uniform sampler2D trail_size_modifier;\n";
+ }
+
+ if (trail_color_modifier.is_valid()) {
+ code += "uniform sampler2D trail_color_modifier;\n";
+ }
+
+ //need a random function
+ code += "\n\n";
+ code += "float rand_from_seed(inout uint seed) {\n";
+ code += " int k;\n";
+ code += " int s = int(seed);\n";
+ code += " if (s == 0)\n";
+ code += " s = 305420679;\n";
+ code += " k = s / 127773;\n";
+ code += " s = 16807 * (s - k * 127773) - 2836 * k;\n";
+ code += " if (s < 0)\n";
+ code += " s += 2147483647;\n";
+ code += " seed = uint(s);\n";
+ code += " return float(seed % uint(65536)) / 65535.0;\n";
+ 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";
+ code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
+ code += " x = (x >> uint(16)) ^ x;\n";
+ code += " return x;\n";
+ code += "}\n";
+ code += "\n";
+
+ code += "void vertex() {\n";
+ code += " uint base_number = NUMBER / uint(trail_divisor);\n";
+ code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
+ code += " float angle_rand = rand_from_seed(alt_seed);\n";
+ 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) {
+ code += " int point = min(emission_texture_point_count - 1, int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n";
+ code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
+ code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
+ }
+ code += " if (RESTART) {\n";
+
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_linear_velocity = 0.0;\n";
+
+ if (tex_parameters[PARAM_ANGLE].is_valid())
+ code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_angle = 0.0;\n";
+
+ if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
+ code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ 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_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_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 * 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) {
+ case EMISSION_SHAPE_POINT: {
+ //do none
+ } break;
+ case EMISSION_SHAPE_SPHERE: {
+ code += " TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0)) * emission_sphere_radius;\n";
+ } break;
+ case EMISSION_SHAPE_BOX: {
+ code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
+ } break;
+ case EMISSION_SHAPE_POINTS:
+ case EMISSION_SHAPE_DIRECTED_POINTS: {
+ code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
+
+ if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
+ if (flags[FLAG_DISABLE_Z]) {
+
+ code += " mat2 rotm;";
+ code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
+ code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
+ code += " VELOCITY.xy = rotm * VELOCITY.xy;\n";
+ } else {
+ code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
+ code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n";
+ code += " vec3 tangent = normalize(cross(v0, normal));\n";
+ code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
+ code += " VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
+ }
+ }
+ } break;
+ }
+ code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+ if (flags[FLAG_DISABLE_Z]) {
+ code += " VELOCITY.z = 0.0;\n";
+ code += " TRANSFORM[3].z = 0.0;\n";
+ }
+
+ code += " } else {\n";
+
+ code += " CUSTOM.y += DELTA / LIFETIME;\n";
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid())
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_linear_velocity = 0.0;\n";
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid())
+ code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_orbit_velocity = 0.0;\n";
+ }
+
+ if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid())
+ code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_angular_velocity = 0.0;\n";
+
+ if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid())
+ code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_linear_accel = 0.0;\n";
+
+ if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid())
+ code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_radial_accel = 0.0;\n";
+
+ if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid())
+ code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_tangent_accel = 0.0;\n";
+
+ if (tex_parameters[PARAM_DAMPING].is_valid())
+ code += " float tex_damping = textureLod(damping_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_damping = 0.0;\n";
+
+ if (tex_parameters[PARAM_ANGLE].is_valid())
+ code += " float tex_angle = textureLod(angle_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_angle = 0.0;\n";
+
+ if (tex_parameters[PARAM_ANIM_SPEED].is_valid())
+ code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_anim_speed = 0.0;\n";
+
+ if (tex_parameters[PARAM_ANIM_OFFSET].is_valid())
+ code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_anim_offset = 0.0;\n";
+
+ code += " vec3 force = gravity;\n";
+ code += " vec3 pos = TRANSFORM[3].xyz;\n";
+ if (flags[FLAG_DISABLE_Z]) {
+ code += " pos.z = 0.0;\n";
+ }
+ code += " // apply linear acceleration\n";
+ code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);\n";
+ code += " // apply radial acceleration\n";
+ code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
+ code += " vec3 diff = pos - org;\n";
+ code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
+ code += " // apply tangential acceleration;\n";
+ if (flags[FLAG_DISABLE_Z]) {
+ code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+
+ } else {
+ code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n";
+ code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ }
+ code += " // apply attractor forces\n";
+ code += " VELOCITY += force * DELTA;\n";
+ code += " // orbit velocity\n";
+ if (flags[FLAG_DISABLE_Z]) {
+
+ 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 * 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";
+ code += " }\n";
+ }
+
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
+ }
+ code += " if (damping + tex_damping > 0.0) {\n";
+ code += " float v = length(VELOCITY);\n";
+ code += " float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);\n";
+ code += " v -= damp * DELTA;\n";
+ code += " if (v < 0.0) {\n";
+ code += " VELOCITY = vec3(0.0);\n";
+ code += " } else {\n";
+ code += " VELOCITY = normalize(VELOCITY) * v;\n";
+ code += " }\n";
+ 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 * 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
+
+ } else {
+ code += " CUSTOM.z = clamp(CUSTOM.z, 0.0, 1.0);\n"; // 0 to 1 only
+ }
+ code += " }\n";
+ // apply color
+ // apply hue rotation
+ if (tex_parameters[PARAM_SCALE].is_valid())
+ code += " float tex_scale = textureLod(scale_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_scale = 1.0;\n";
+
+ if (tex_parameters[PARAM_HUE_VARIATION].is_valid())
+ code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n";
+ else
+ code += " float tex_hue_variation = 0.0;\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";
+ code += " vec4(0.299, 0.587, 0.114, 0.0),\n";
+ code += " vec4(0.299, 0.587, 0.114, 0.0),\n";
+ code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n";
+ code += " mat4(vec4(0.701, -0.587, -0.114, 0.0),\n";
+ code += " vec4(-0.299, 0.413, -0.114, 0.0),\n";
+ code += " vec4(-0.300, -0.588, 0.886, 0.0),\n";
+ code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n";
+ code += " mat4(vec4(0.168, 0.330, -0.497, 0.0),\n";
+ code += " vec4(-0.328, 0.035, 0.292, 0.0),\n";
+ 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 = hue_rot_mat * textureLod(color_ramp, vec2(CUSTOM.y, 0.0), 0.0);\n";
+ } else {
+ 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";
+ }
+ if (trail_color_modifier.is_valid()) {
+ code += " if (trail_divisor > 1) {\n";
+ code += " COLOR *= textureLod(trail_color_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0);\n";
+ code += " }\n";
+ }
+ code += "\n";
+
+ if (flags[FLAG_DISABLE_Z]) {
+
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ code += " if (length(VELOCITY) > 0.0) {\n";
+ code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n";
+ code += " } else {\n";
+ code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n";
+ code += " }\n";
+ code += " TRANSFORM[0].xyz = normalize(cross(TRANSFORM[1].xyz, TRANSFORM[2].xyz));\n";
+ code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n";
+ } else {
+ code += " TRANSFORM[0] = vec4(cos(CUSTOM.x), -sin(CUSTOM.x), 0.0, 0.0);\n";
+ code += " TRANSFORM[1] = vec4(sin(CUSTOM.x), cos(CUSTOM.x), 0.0, 0.0);\n";
+ code += " TRANSFORM[2] = vec4(0.0, 0.0, 1.0, 0.0);\n";
+ }
+
+ } else {
+ // orient particle Y towards velocity
+ if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) {
+ code += " if (length(VELOCITY) > 0.0) {\n";
+ code += " TRANSFORM[1].xyz = normalize(VELOCITY);\n";
+ code += " } else {\n";
+ code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n";
+ code += " }\n";
+ code += " if (TRANSFORM[1].xyz == normalize(TRANSFORM[0].xyz)) {\n";
+ code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz), normalize(TRANSFORM[2].xyz)));\n";
+ code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz), normalize(TRANSFORM[1].xyz)));\n";
+ code += " } else {\n";
+ code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz), normalize(TRANSFORM[1].xyz)));\n";
+ code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz), normalize(TRANSFORM[2].xyz)));\n";
+ code += " }\n";
+ } else {
+ code += " TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);\n";
+ code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n";
+ code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n";
+ }
+ // turn particle by rotation in Y
+ if (flags[FLAG_ROTATE_Y]) {
+ code += " TRANSFORM = TRANSFORM * mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ }
+ }
+ //scale by scale
+ code += " float base_scale = mix(scale * tex_scale, 1.0, scale_random * scale_rand);\n";
+ code += " if (base_scale == 0.0) {\n";
+ code += " base_scale = 0.000001;\n";
+ code += " }\n";
+ if (trail_size_modifier.is_valid()) {
+ code += " if (trail_divisor > 1) {\n";
+ code += " base_scale *= textureLod(trail_size_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0).r;\n";
+ code += " }\n";
+ }
+
+ code += " TRANSFORM[0].xyz *= base_scale;\n";
+ code += " TRANSFORM[1].xyz *= base_scale;\n";
+ code += " TRANSFORM[2].xyz *= base_scale;\n";
+ if (flags[FLAG_DISABLE_Z]) {
+ code += " VELOCITY.z = 0.0;\n";
+ code += " TRANSFORM[3].z = 0.0;\n";
+ }
+ code += "}\n";
+ code += "\n";
+
+ ShaderData shader_data;
+ shader_data.shader = VS::get_singleton()->shader_create();
+ shader_data.users = 1;
+
+ VS::get_singleton()->shader_set_code(shader_data.shader, code);
+
+ shader_map[mk] = shader_data;
+
+ VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+}
+
+void ParticlesMaterial::flush_changes() {
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ while (dirty_materials.first()) {
+
+ dirty_materials.first()->self()->_update_shader();
+ }
+
+ if (material_mutex)
+ material_mutex->unlock();
+}
+
+void ParticlesMaterial::_queue_shader_change() {
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ if (!element.in_list()) {
+ dirty_materials.add(&element);
+ }
+
+ if (material_mutex)
+ material_mutex->unlock();
+}
+
+bool ParticlesMaterial::_is_shader_dirty() const {
+
+ bool dirty = false;
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ dirty = element.in_list();
+
+ if (material_mutex)
+ material_mutex->unlock();
+
+ return dirty;
+}
+
+void ParticlesMaterial::set_spread(float p_spread) {
+
+ spread = p_spread;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
+}
+
+float ParticlesMaterial::get_spread() const {
+
+ return spread;
+}
+
+void ParticlesMaterial::set_flatness(float p_flatness) {
+
+ flatness = p_flatness;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
+}
+float ParticlesMaterial::get_flatness() const {
+
+ return flatness;
+}
+
+void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ parameters[p_param] = p_value;
+
+ switch (p_param) {
+ case PARAM_INITIAL_LINEAR_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value);
+ } break;
+ case PARAM_ANGULAR_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value);
+ } break;
+ case PARAM_ORBIT_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value);
+ } break;
+ case PARAM_LINEAR_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value);
+ } break;
+ case PARAM_RADIAL_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value);
+ } break;
+ case PARAM_TANGENTIAL_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value);
+ } break;
+ case PARAM_DAMPING: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value);
+ } break;
+ case PARAM_ANGLE: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value);
+ } break;
+ case PARAM_SCALE: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value);
+ } break;
+ case PARAM_HUE_VARIATION: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value);
+ } break;
+ case PARAM_ANIM_SPEED: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value);
+ } break;
+ case PARAM_ANIM_OFFSET: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
+ } break;
+ }
+}
+float ParticlesMaterial::get_param(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return parameters[p_param];
+}
+
+void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ randomness[p_param] = p_value;
+
+ switch (p_param) {
+ case PARAM_INITIAL_LINEAR_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value);
+ } break;
+ case PARAM_ANGULAR_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value);
+ } break;
+ case PARAM_ORBIT_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value);
+ } break;
+ case PARAM_LINEAR_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value);
+ } break;
+ case PARAM_RADIAL_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value);
+ } break;
+ case PARAM_TANGENTIAL_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value);
+ } break;
+ case PARAM_DAMPING: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value);
+ } break;
+ case PARAM_ANGLE: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value);
+ } break;
+ case PARAM_SCALE: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value);
+ } break;
+ case PARAM_HUE_VARIATION: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value);
+ } break;
+ case PARAM_ANIM_SPEED: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value);
+ } break;
+ case PARAM_ANIM_OFFSET: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
+ } break;
+ }
+}
+float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
+
+ return randomness[p_param];
+}
+
+static void _adjust_curve_range(const Ref<Texture> &p_texture, float p_min, float p_max) {
+
+ Ref<CurveTexture> curve_tex = p_texture;
+ if (!curve_tex.is_valid())
+ return;
+
+ curve_tex->ensure_default_setup(p_min, p_max);
+}
+
+void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> &p_texture) {
+
+ ERR_FAIL_INDEX(p_param, PARAM_MAX);
+
+ tex_parameters[p_param] = p_texture;
+
+ switch (p_param) {
+ case PARAM_INITIAL_LINEAR_VELOCITY: {
+ //do none for this one
+ } break;
+ case PARAM_ANGULAR_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture);
+ _adjust_curve_range(p_texture, -360, 360);
+ } break;
+ case PARAM_ORBIT_VELOCITY: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture);
+ _adjust_curve_range(p_texture, -500, 500);
+ } break;
+ case PARAM_LINEAR_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture);
+ _adjust_curve_range(p_texture, -200, 200);
+ } break;
+ case PARAM_RADIAL_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture);
+ _adjust_curve_range(p_texture, -200, 200);
+ } break;
+ case PARAM_TANGENTIAL_ACCEL: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture);
+ _adjust_curve_range(p_texture, -200, 200);
+ } break;
+ case PARAM_DAMPING: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture);
+ _adjust_curve_range(p_texture, 0, 100);
+ } break;
+ case PARAM_ANGLE: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture);
+ _adjust_curve_range(p_texture, -360, 360);
+ } break;
+ case PARAM_SCALE: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture);
+
+ Ref<CurveTexture> curve_tex = p_texture;
+ if (curve_tex.is_valid()) {
+ curve_tex->ensure_default_setup();
+ }
+
+ } break;
+ case PARAM_HUE_VARIATION: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture);
+ _adjust_curve_range(p_texture, -1, 1);
+ } break;
+ case PARAM_ANIM_SPEED: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture);
+ _adjust_curve_range(p_texture, 0, 200);
+ } break;
+ case PARAM_ANIM_OFFSET: {
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
+ } break;
+ }
+
+ _queue_shader_change();
+}
+Ref<Texture> ParticlesMaterial::get_param_texture(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture>());
+
+ return tex_parameters[p_param];
+}
+
+void ParticlesMaterial::set_color(const Color &p_color) {
+
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
+ color = p_color;
+}
+
+Color ParticlesMaterial::get_color() const {
+
+ return color;
+}
+
+void ParticlesMaterial::set_color_ramp(const Ref<Texture> &p_texture) {
+
+ color_ramp = p_texture;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture);
+ _queue_shader_change();
+ _change_notify();
+}
+
+Ref<Texture> ParticlesMaterial::get_color_ramp() const {
+
+ return color_ramp;
+}
+
+void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) {
+ ERR_FAIL_INDEX(p_flag, FLAG_MAX);
+ flags[p_flag] = p_enable;
+ _queue_shader_change();
+ if (p_flag == FLAG_DISABLE_Z) {
+ _change_notify();
+ }
+}
+
+bool ParticlesMaterial::get_flag(Flags p_flag) const {
+ ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
+ return flags[p_flag];
+}
+
+void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
+
+ emission_shape = p_shape;
+ _change_notify();
+ _queue_shader_change();
+}
+
+void ParticlesMaterial::set_emission_sphere_radius(float p_radius) {
+
+ emission_sphere_radius = p_radius;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
+}
+
+void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
+
+ emission_box_extents = p_extents;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
+}
+
+void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) {
+
+ emission_point_texture = p_points;
+ 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;
+ 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;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors);
+ _queue_shader_change();
+}
+
+void ParticlesMaterial::set_emission_point_count(int p_count) {
+
+ emission_point_count = p_count;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
+}
+
+ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const {
+
+ return emission_shape;
+}
+
+float ParticlesMaterial::get_emission_sphere_radius() const {
+
+ return emission_sphere_radius;
+}
+Vector3 ParticlesMaterial::get_emission_box_extents() const {
+
+ return emission_box_extents;
+}
+Ref<Texture> ParticlesMaterial::get_emission_point_texture() const {
+
+ return emission_point_texture;
+}
+Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const {
+
+ return emission_normal_texture;
+}
+
+Ref<Texture> ParticlesMaterial::get_emission_color_texture() const {
+
+ return emission_color_texture;
+}
+
+int ParticlesMaterial::get_emission_point_count() const {
+
+ return emission_point_count;
+}
+
+void ParticlesMaterial::set_trail_divisor(int p_divisor) {
+
+ trail_divisor = p_divisor;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor);
+}
+
+int ParticlesMaterial::get_trail_divisor() const {
+
+ return trail_divisor;
+}
+
+void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) {
+
+ trail_size_modifier = p_trail_size_modifier;
+
+ Ref<CurveTexture> curve = trail_size_modifier;
+ if (curve.is_valid()) {
+ curve->ensure_default_setup();
+ }
+
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
+ _queue_shader_change();
+}
+
+Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
+
+ return trail_size_modifier;
+}
+
+void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
+
+ trail_color_modifier = p_trail_color_modifier;
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
+ _queue_shader_change();
+}
+
+Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const {
+
+ return trail_color_modifier;
+}
+
+void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
+
+ gravity = p_gravity;
+ Vector3 gset = gravity;
+ if (gset == Vector3()) {
+ gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations
+ }
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset);
+}
+
+Vector3 ParticlesMaterial::get_gravity() const {
+
+ return gravity;
+}
+
+RID ParticlesMaterial::get_shader_rid() const {
+
+ ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
+ return shader_map[current_key].shader;
+}
+
+void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "color" && color_ramp.is_valid()) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ property.usage = 0;
+ }
+
+ if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ property.usage = 0;
+ }
+
+ if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ property.usage = 0;
+ }
+
+ if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
+ property.usage = 0;
+ }
+}
+
+Shader::Mode ParticlesMaterial::get_shader_mode() const {
+
+ return Shader::MODE_PARTICLES;
+}
+
+void ParticlesMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread);
+ ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread);
+
+ ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness);
+ ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
+
+ ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ParticlesMaterial::set_param);
+ ClassDB::bind_method(D_METHOD("get_param", "param"), &ParticlesMaterial::get_param);
+
+ ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &ParticlesMaterial::set_param_randomness);
+ ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &ParticlesMaterial::get_param_randomness);
+
+ ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture);
+ ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
+
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color);
+
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp);
+
+ ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag);
+ ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag);
+
+ ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape);
+
+ ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius);
+
+ ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents);
+
+ ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture);
+
+ ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture);
+
+ ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture);
+
+ ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count);
+ ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count);
+
+ ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor);
+ ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor);
+
+ ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture"), &ParticlesMaterial::set_trail_size_modifier);
+ ClassDB::bind_method(D_METHOD("get_trail_size_modifier"), &ParticlesMaterial::get_trail_size_modifier);
+
+ ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture"), &ParticlesMaterial::set_trail_color_modifier);
+ ClassDB::bind_method(D_METHOD("get_trail_color_modifier"), &ParticlesMaterial::get_trail_color_modifier);
+
+ ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity);
+
+ ADD_GROUP("Trail", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier");
+ ADD_GROUP("Emission Shape", "emission_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_color_texture", "get_emission_color_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count");
+ ADD_GROUP("Flags", "flag_");
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z);
+ ADD_GROUP("Spread", "");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness");
+ 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,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,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,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,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,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", "");
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING);
+ 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,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,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", "");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp");
+
+ ADD_GROUP("Hue Variation", "hue_");
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION);
+ 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,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);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP);
+
+ BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL);
+ BIND_ENUM_CONSTANT(PARAM_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_ANGLE);
+ BIND_ENUM_CONSTANT(PARAM_SCALE);
+ BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED);
+ BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_MAX);
+
+ BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
+ BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(FLAG_MAX);
+
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS);
+ BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS);
+}
+
+ParticlesMaterial::ParticlesMaterial() :
+ element(this) {
+
+ set_spread(45);
+ set_flatness(0);
+ set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1);
+ set_param(PARAM_ORBIT_VELOCITY, 0);
+ set_param(PARAM_LINEAR_ACCEL, 0);
+ set_param(PARAM_RADIAL_ACCEL, 0);
+ set_param(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param(PARAM_DAMPING, 0);
+ set_param(PARAM_ANGLE, 0);
+ set_param(PARAM_SCALE, 1);
+ set_param(PARAM_HUE_VARIATION, 0);
+ set_param(PARAM_ANIM_SPEED, 0);
+ set_param(PARAM_ANIM_OFFSET, 0);
+ set_emission_shape(EMISSION_SHAPE_POINT);
+ set_emission_sphere_radius(1);
+ set_emission_box_extents(Vector3(1, 1, 1));
+ set_trail_divisor(1);
+ set_gravity(Vector3(0, -9.8, 0));
+ emission_point_count = 1;
+
+ for (int i = 0; i < PARAM_MAX; i++) {
+ set_param_randomness(Parameter(i), 0);
+ }
+
+ for (int i = 0; i < FLAG_MAX; i++) {
+ flags[i] = false;
+ }
+
+ set_color(Color(1, 1, 1, 1));
+
+ current_key.key = 0;
+ current_key.invalid_key = 1;
+
+ _queue_shader_change();
+}
+
+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/resources/particles_material.h b/scene/resources/particles_material.h
new file mode 100644
index 0000000000..8090926fa3
--- /dev/null
+++ b/scene/resources/particles_material.h
@@ -0,0 +1,302 @@
+/*************************************************************************/
+/* particles_material.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. */
+/*************************************************************************/
+
+#include "rid.h"
+#include "scene/resources/material.h"
+
+#ifndef PARTICLES_MATERIAL_H
+#define PARTICLES_MATERIAL_H
+
+class ParticlesMaterial : public Material {
+
+ GDCLASS(ParticlesMaterial, Material)
+
+public:
+ enum Parameter {
+
+ PARAM_INITIAL_LINEAR_VELOCITY,
+ PARAM_ANGULAR_VELOCITY,
+ PARAM_ORBIT_VELOCITY,
+ PARAM_LINEAR_ACCEL,
+ PARAM_RADIAL_ACCEL,
+ PARAM_TANGENTIAL_ACCEL,
+ PARAM_DAMPING,
+ PARAM_ANGLE,
+ PARAM_SCALE,
+ PARAM_HUE_VARIATION,
+ PARAM_ANIM_SPEED,
+ PARAM_ANIM_OFFSET,
+ PARAM_MAX
+ };
+
+ enum Flags {
+ FLAG_ALIGN_Y_TO_VELOCITY,
+ FLAG_ROTATE_Y,
+ FLAG_DISABLE_Z,
+ FLAG_ANIM_LOOP,
+ FLAG_MAX
+ };
+
+ enum EmissionShape {
+ EMISSION_SHAPE_POINT,
+ EMISSION_SHAPE_SPHERE,
+ EMISSION_SHAPE_BOX,
+ EMISSION_SHAPE_POINTS,
+ EMISSION_SHAPE_DIRECTED_POINTS,
+ };
+
+private:
+ union MaterialKey {
+
+ struct {
+ uint32_t texture_mask : 16;
+ uint32_t texture_color : 1;
+ uint32_t flags : 4;
+ uint32_t emission_shape : 2;
+ uint32_t trail_size_texture : 1;
+ uint32_t trail_color_texture : 1;
+ uint32_t invalid_key : 1;
+ uint32_t has_emission_color : 1;
+ };
+
+ uint32_t key;
+
+ bool operator<(const MaterialKey &p_key) const {
+ return key < p_key.key;
+ }
+ };
+
+ struct ShaderData {
+ RID shader;
+ int users;
+ };
+
+ static Map<MaterialKey, ShaderData> shader_map;
+
+ MaterialKey current_key;
+
+ _FORCE_INLINE_ MaterialKey _compute_key() const {
+
+ MaterialKey mk;
+ mk.key = 0;
+ for (int i = 0; i < PARAM_MAX; i++) {
+ if (tex_parameters[i].is_valid()) {
+ mk.texture_mask |= (1 << i);
+ }
+ }
+ for (int i = 0; i < FLAG_MAX; i++) {
+ if (flags[i]) {
+ mk.flags |= (1 << i);
+ }
+ }
+
+ mk.texture_color = color_ramp.is_valid() ? 1 : 0;
+ mk.emission_shape = emission_shape;
+ mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0;
+ mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0;
+ mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
+
+ return mk;
+ }
+
+ static Mutex *material_mutex;
+ static SelfList<ParticlesMaterial>::List dirty_materials;
+
+ struct ShaderNames {
+ StringName spread;
+ StringName flatness;
+ StringName initial_linear_velocity;
+ StringName initial_angle;
+ StringName angular_velocity;
+ StringName orbit_velocity;
+ StringName linear_accel;
+ StringName radial_accel;
+ StringName tangent_accel;
+ StringName damping;
+ StringName scale;
+ StringName hue_variation;
+ StringName anim_speed;
+ StringName anim_offset;
+
+ StringName initial_linear_velocity_random;
+ StringName initial_angle_random;
+ StringName angular_velocity_random;
+ StringName orbit_velocity_random;
+ StringName linear_accel_random;
+ StringName radial_accel_random;
+ StringName tangent_accel_random;
+ StringName damping_random;
+ StringName scale_random;
+ StringName hue_variation_random;
+ StringName anim_speed_random;
+ StringName anim_offset_random;
+
+ StringName angle_texture;
+ StringName angular_velocity_texture;
+ StringName orbit_velocity_texture;
+ StringName linear_accel_texture;
+ StringName radial_accel_texture;
+ StringName tangent_accel_texture;
+ StringName damping_texture;
+ StringName scale_texture;
+ StringName hue_variation_texture;
+ StringName anim_speed_texture;
+ StringName anim_offset_texture;
+
+ StringName color;
+ StringName color_ramp;
+
+ StringName emission_sphere_radius;
+ StringName emission_box_extents;
+ StringName emission_texture_point_count;
+ StringName emission_texture_points;
+ StringName emission_texture_normal;
+ StringName emission_texture_color;
+
+ StringName trail_divisor;
+ StringName trail_size_modifier;
+ StringName trail_color_modifier;
+
+ StringName gravity;
+ };
+
+ static ShaderNames *shader_names;
+
+ SelfList<ParticlesMaterial> element;
+
+ void _update_shader();
+ _FORCE_INLINE_ void _queue_shader_change();
+ _FORCE_INLINE_ bool _is_shader_dirty() const;
+
+ float spread;
+ float flatness;
+
+ float parameters[PARAM_MAX];
+ float randomness[PARAM_MAX];
+
+ Ref<Texture> tex_parameters[PARAM_MAX];
+ Color color;
+ Ref<Texture> color_ramp;
+
+ bool flags[FLAG_MAX];
+
+ EmissionShape emission_shape;
+ float emission_sphere_radius;
+ Vector3 emission_box_extents;
+ Ref<Texture> emission_point_texture;
+ Ref<Texture> emission_normal_texture;
+ Ref<Texture> emission_color_texture;
+ int emission_point_count;
+
+ bool anim_loop;
+
+ int trail_divisor;
+
+ Ref<CurveTexture> trail_size_modifier;
+ Ref<GradientTexture> trail_color_modifier;
+
+ Vector3 gravity;
+
+ //do not save emission points here
+
+protected:
+ static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_spread(float p_spread);
+ float get_spread() const;
+
+ void set_flatness(float p_flatness);
+ float get_flatness() const;
+
+ void set_param(Parameter p_param, float p_value);
+ float get_param(Parameter p_param) const;
+
+ void set_param_randomness(Parameter p_param, float p_value);
+ float get_param_randomness(Parameter p_param) const;
+
+ void set_param_texture(Parameter p_param, const Ref<Texture> &p_texture);
+ Ref<Texture> get_param_texture(Parameter p_param) const;
+
+ void set_color(const Color &p_color);
+ Color get_color() const;
+
+ void set_color_ramp(const Ref<Texture> &p_texture);
+ Ref<Texture> get_color_ramp() const;
+
+ void set_flag(Flags p_flag, bool p_enable);
+ bool get_flag(Flags p_flag) const;
+
+ void set_emission_shape(EmissionShape p_shape);
+ void set_emission_sphere_radius(float p_radius);
+ void set_emission_box_extents(Vector3 p_extents);
+ void set_emission_point_texture(const Ref<Texture> &p_points);
+ void set_emission_normal_texture(const Ref<Texture> &p_normals);
+ void set_emission_color_texture(const Ref<Texture> &p_colors);
+ void set_emission_point_count(int p_count);
+
+ EmissionShape get_emission_shape() const;
+ float get_emission_sphere_radius() const;
+ Vector3 get_emission_box_extents() const;
+ Ref<Texture> get_emission_point_texture() const;
+ Ref<Texture> get_emission_normal_texture() const;
+ Ref<Texture> get_emission_color_texture() const;
+ int get_emission_point_count() const;
+
+ void set_trail_divisor(int p_divisor);
+ int get_trail_divisor() const;
+
+ void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier);
+ Ref<CurveTexture> get_trail_size_modifier() const;
+
+ void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier);
+ Ref<GradientTexture> get_trail_color_modifier() const;
+
+ void set_gravity(const Vector3 &p_gravity);
+ Vector3 get_gravity() const;
+
+ static void init_shaders();
+ static void finish_shaders();
+ static void flush_changes();
+
+ RID get_shader_rid() const;
+
+ virtual Shader::Mode get_shader_mode() const;
+
+ ParticlesMaterial();
+ ~ParticlesMaterial();
+};
+
+VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
+VARIANT_ENUM_CAST(ParticlesMaterial::Flags)
+VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
+
+#endif // PARTICLES_MATERIAL_H
diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp
new file mode 100644
index 0000000000..03b3589727
--- /dev/null
+++ b/scene/resources/physics_material.cpp
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* physics_material.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 "physics_material.h"
+
+void PhysicsMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicsMaterial::set_friction);
+ ClassDB::bind_method(D_METHOD("get_friction"), &PhysicsMaterial::get_friction);
+
+ ClassDB::bind_method(D_METHOD("set_rough", "rough"), &PhysicsMaterial::set_rough);
+ ClassDB::bind_method(D_METHOD("is_rough"), &PhysicsMaterial::is_rough);
+
+ ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicsMaterial::set_bounce);
+ ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicsMaterial::get_bounce);
+
+ ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent);
+ ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent");
+}
+
+void PhysicsMaterial::set_friction(real_t p_val) {
+ friction = p_val;
+ emit_changed();
+}
+
+void PhysicsMaterial::set_rough(bool p_val) {
+ rough = p_val;
+ emit_changed();
+}
+
+void PhysicsMaterial::set_bounce(real_t p_val) {
+ bounce = p_val;
+ emit_changed();
+}
+
+void PhysicsMaterial::set_absorbent(bool p_val) {
+ absorbent = p_val;
+ emit_changed();
+}
+
+PhysicsMaterial::PhysicsMaterial() :
+ friction(1),
+ rough(false),
+ bounce(0),
+ absorbent(false) {}
diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h
new file mode 100644
index 0000000000..c882e2081a
--- /dev/null
+++ b/scene/resources/physics_material.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* physics_material.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 physics_material_override_H
+#define physics_material_override_H
+
+#include "resource.h"
+#include "servers/physics_server.h"
+
+class PhysicsMaterial : public Resource {
+
+ GDCLASS(PhysicsMaterial, Resource);
+ OBJ_SAVE_TYPE(PhysicsMaterial);
+ RES_BASE_EXTENSION("phymat");
+
+ real_t friction;
+ bool rough;
+ real_t bounce;
+ bool absorbent;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_friction(real_t p_val);
+ _FORCE_INLINE_ real_t get_friction() const { return friction; }
+
+ void set_rough(bool p_val);
+ _FORCE_INLINE_ bool is_rough() const { return rough; }
+
+ _FORCE_INLINE_ real_t computed_friction() const {
+ return rough ? -friction : friction;
+ }
+
+ void set_bounce(real_t p_val);
+ _FORCE_INLINE_ real_t get_bounce() const { return bounce; }
+
+ void set_absorbent(bool p_val);
+ _FORCE_INLINE_ bool is_absorbent() const { return absorbent; }
+
+ _FORCE_INLINE_ real_t computed_bounce() const {
+ return absorbent ? -bounce : bounce;
+ }
+
+ PhysicsMaterial();
+};
+
+#endif // physics_material_override_H
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 6fea2e1a8e..44f9ebaf33 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -65,8 +65,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
for (int i = 0; i < p_points.size(); i++) {
- points[i].pos = p_points[i];
- points[i].penalty = 0;
+ points.write[i].pos = p_points[i];
+ points.write[i].penalty = 0;
outside_point.x = i == 0 ? p_points[0].x : (MAX(p_points[i].x, outside_point.x));
outside_point.y = i == 0 ? p_points[0].y : (MAX(p_points[i].y, outside_point.y));
@@ -88,8 +88,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
Edge e(p_connections[i], p_connections[i + 1]);
ERR_FAIL_INDEX(e.points[0], point_count);
ERR_FAIL_INDEX(e.points[1], point_count);
- points[p_connections[i]].connections.insert(p_connections[i + 1]);
- points[p_connections[i + 1]].connections.insert(p_connections[i]);
+ points.write[p_connections[i]].connections.insert(p_connections[i + 1]);
+ points.write[p_connections[i + 1]].connections.insert(p_connections[i]);
edges.insert(e);
}
@@ -126,8 +126,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int>
}
if (valid) {
- points[i].connections.insert(j);
- points[j].connections.insert(i);
+ points.write[i].connections.insert(j);
+ points.write[j].connections.insert(i);
}
}
}
@@ -227,21 +227,21 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
int aidx = points.size() - 2;
int bidx = points.size() - 1;
- points[aidx].pos = from;
- points[bidx].pos = to;
- points[aidx].distance = 0;
- points[bidx].distance = 0;
- points[aidx].prev = -1;
- points[bidx].prev = -1;
- points[aidx].penalty = 0;
- points[bidx].penalty = 0;
+ points.write[aidx].pos = from;
+ points.write[bidx].pos = to;
+ points.write[aidx].distance = 0;
+ points.write[bidx].distance = 0;
+ points.write[aidx].prev = -1;
+ points.write[bidx].prev = -1;
+ points.write[aidx].penalty = 0;
+ points.write[bidx].penalty = 0;
for (int i = 0; i < points.size() - 2; i++) {
bool valid_a = true;
bool valid_b = true;
- points[i].prev = -1;
- points[i].distance = 0;
+ points.write[i].prev = -1;
+ points.write[i].distance = 0;
if (!_is_point_inside(from * 0.5 + points[i].pos * 0.5)) {
valid_a = false;
@@ -292,26 +292,26 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
}
if (valid_a) {
- points[i].connections.insert(aidx);
- points[aidx].connections.insert(i);
+ points.write[i].connections.insert(aidx);
+ points.write[aidx].connections.insert(i);
}
if (valid_b) {
- points[i].connections.insert(bidx);
- points[bidx].connections.insert(i);
+ points.write[i].connections.insert(bidx);
+ points.write[bidx].connections.insert(i);
}
}
//solve graph
Set<int> open_list;
- points[aidx].distance = 0;
- points[aidx].prev = aidx;
+ points.write[aidx].distance = 0;
+ points.write[aidx].prev = aidx;
for (Set<int>::Element *E = points[aidx].connections.front(); E; E = E->next()) {
open_list.insert(E->get());
- points[E->get()].distance = from.distance_to(points[E->get()].pos);
- points[E->get()].prev = aidx;
+ points.write[E->get()].distance = from.distance_to(points[E->get()].pos);
+ points.write[E->get()].prev = aidx;
}
bool found_route = false;
@@ -342,12 +342,12 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
}
}
- Point &np = points[least_cost_point];
+ const Point &np = points[least_cost_point];
//open the neighbours for search
for (Set<int>::Element *E = np.connections.front(); E; E = E->next()) {
- Point &p = points[E->get()];
+ Point &p = points.write[E->get()];
float distance = np.pos.distance_to(p.pos) + np.distance;
if (p.prev != -1) {
@@ -392,18 +392,18 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
for (int i = 0; i < points.size() - 2; i++) {
- points[i].connections.erase(aidx);
- points[i].connections.erase(bidx);
- points[i].prev = -1;
- points[i].distance = 0;
+ points.write[i].connections.erase(aidx);
+ points.write[i].connections.erase(bidx);
+ points.write[i].prev = -1;
+ points.write[i].distance = 0;
}
- points[aidx].connections.clear();
- points[aidx].prev = -1;
- points[aidx].distance = 0;
- points[bidx].connections.clear();
- points[bidx].prev = -1;
- points[bidx].distance = 0;
+ points.write[aidx].connections.clear();
+ points.write[aidx].prev = -1;
+ points.write[aidx].distance = 0;
+ points.write[bidx].connections.clear();
+ points.write[bidx].prev = -1;
+ points.write[bidx].distance = 0;
return path;
}
@@ -427,13 +427,13 @@ void PolygonPathFinder::_set_data(const Dictionary &p_data) {
PoolVector<Vector2>::Read pr = p.read();
for (int i = 0; i < pc; i++) {
- points[i].pos = pr[i];
+ points.write[i].pos = pr[i];
PoolVector<int> con = c[i];
PoolVector<int>::Read cr = con.read();
int cc = con.size();
for (int j = 0; j < cc; j++) {
- points[i].connections.insert(cr[j]);
+ points.write[i].connections.insert(cr[j]);
}
}
@@ -443,7 +443,7 @@ void PolygonPathFinder::_set_data(const Dictionary &p_data) {
if (penalties.size() == pc) {
PoolVector<float>::Read pr = penalties.read();
for (int i = 0; i < pc; i++) {
- points[i].penalty = pr[i];
+ points.write[i].penalty = pr[i];
}
}
}
@@ -566,7 +566,7 @@ Rect2 PolygonPathFinder::get_bounds() const {
void PolygonPathFinder::set_point_penalty(int p_point, float p_penalty) {
ERR_FAIL_INDEX(p_point, points.size() - 2);
- points[p_point].penalty = p_penalty;
+ points.write[p_point].penalty = p_penalty;
}
float PolygonPathFinder::get_point_penalty(int p_point) const {
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
index 597866eb74..fd9989fe72 100644
--- a/scene/resources/scene_format_text.cpp
+++ b/scene/resources/scene_format_text.cpp
@@ -896,7 +896,7 @@ static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p
CharString utf8 = p_string.utf8();
if (p_bit_on_len) {
- f->store_32(utf8.length() + 1 | 0x80000000);
+ f->store_32((utf8.length() + 1) | 0x80000000);
} else {
f->store_32(utf8.length() + 1);
}
@@ -1523,7 +1523,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) {
- sorted_er[E->get()] = E->key();
+ sorted_er.write[E->get()] = E->key();
}
for (int i = 0; i < sorted_er.size(); i++) {
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 36740a307b..f53f03c1c8 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -54,16 +54,20 @@ void Shader::set_code(const String &p_code) {
VisualServer::get_singleton()->shader_set_code(shader, p_code);
params_cache_dirty = true;
- emit_signal(SceneStringNames::get_singleton()->changed);
+
+ emit_changed();
}
String Shader::get_code() const {
+ _update_shader();
return VisualServer::get_singleton()->shader_get_code(shader);
}
void Shader::get_param_list(List<PropertyInfo> *p_params) const {
+ _update_shader();
+
List<PropertyInfo> local;
VisualServer::get_singleton()->shader_get_param_list(shader, &local);
params_cache.clear();
@@ -72,6 +76,9 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
for (List<PropertyInfo>::Element *E = local.front(); E; E = E->next()) {
PropertyInfo pi = E->get();
+ if (default_textures.has(pi.name)) { //do not show default textures
+ continue;
+ }
pi.name = "shader_param/" + pi.name;
params_cache[pi.name] = E->get().name;
if (p_params) {
@@ -86,6 +93,8 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
RID Shader::get_rid() const {
+ _update_shader();
+
return shader;
}
@@ -98,6 +107,8 @@ void Shader::set_default_texture_param(const StringName &p_param, const Ref<Text
default_textures.erase(p_param);
VS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID());
}
+
+ emit_changed();
}
Ref<Texture> Shader::get_default_texture_param(const StringName &p_param) const {
@@ -120,6 +131,9 @@ bool Shader::has_param(const StringName &p_param) const {
return params_cache.has(p_param);
}
+void Shader::_update_shader() const {
+}
+
void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mode"), &Shader::get_mode);
@@ -227,5 +241,5 @@ void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource,
}
bool ResourceFormatSaverShader::recognize(const RES &p_resource) const {
- return Object::cast_to<Shader>(*p_resource) != NULL;
+ return p_resource->get_class_name() == "Shader"; //only shader, not inherited
}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 248a6f0125..efc5da7753 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -61,12 +61,13 @@ private:
mutable Map<StringName, StringName> params_cache; //map a shader param to a material param..
Map<StringName, Ref<Texture> > default_textures;
+ virtual void _update_shader() const; //used for visual shader
protected:
static void _bind_methods();
public:
//void set_mode(Mode p_mode);
- Mode get_mode() const;
+ virtual Mode get_mode() const;
void set_code(const String &p_code);
String get_code() const;
diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp
deleted file mode 100644
index 070cc84863..0000000000
--- a/scene/resources/shader_graph.cpp
+++ /dev/null
@@ -1,2596 +0,0 @@
-/*************************************************************************/
-/* shader_graph.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 "shader_graph.h"
-
-#include "scene/scene_string_names.h"
-
-// FIXME: Needs to be ported to the new 3.0 shader API
-#if 0
-Array ShaderGraph::_get_node_list(ShaderType p_type) const {
-
- List<int> nodes;
- get_node_list(p_type,&nodes);
- Array arr(true);
- for (List<int>::Element *E=nodes.front();E;E=E->next())
- arr.push_back(E->get());
- return arr;
-}
-Array ShaderGraph::_get_connections(ShaderType p_type) const {
-
- List<Connection> connections;
- get_node_connections(p_type,&connections);
- Array arr(true);
- for (List<Connection>::Element *E=connections.front();E;E=E->next()) {
-
- Dictionary d(true);
- d["src_id"]=E->get().src_id;
- d["src_slot"]=E->get().src_slot;
- d["dst_id"]=E->get().dst_id;
- d["dst_slot"]=E->get().dst_slot;
- arr.push_back(d);
-
- }
- return arr;
-}
-
-void ShaderGraph::_set_data(const Dictionary &p_data) {
-
- Dictionary d=p_data;
- ERR_FAIL_COND(!d.has("shaders"));
- Array sh=d["shaders"];
- ERR_FAIL_COND(sh.size()!=3);
-
- for(int t=0;t<3;t++) {
- Array data=sh[t];
- ERR_FAIL_COND((data.size()%6)!=0);
- shader[t].node_map.clear();
- for(int i=0;i<data.size();i+=6) {
-
- Node n;
- n.id=data[i+0];
- n.type=NodeType(int(data[i+1]));
- n.pos=data[i+2];
- n.param1=data[i+3];
- n.param2=data[i+4];
-
- Array conns=data[i+5];
- ERR_FAIL_COND((conns.size()%3)!=0);
-
- for(int j=0;j<conns.size();j+=3) {
- SourceSlot ss;
- int ls=conns[j+0];
- if (ls == SLOT_DEFAULT_VALUE) {
- n.defaults[conns[j+1]]=conns[j+2];
- } else {
- ss.id=conns[j+1];
- ss.slot=conns[j+2];
- n.connections[ls]=ss;
- }
- }
- shader[t].node_map[n.id]=n;
-
- }
- }
-
- _pending_update_shader=true;
- _update_shader();
-
-}
-
-Dictionary ShaderGraph::_get_data() const {
-
- Array sh;
- for(int i=0;i<3;i++) {
- Array data;
- int ec = shader[i].node_map.size();
- data.resize(ec*6);
- int idx=0;
- for (Map<int,Node>::Element*E=shader[i].node_map.front();E;E=E->next()) {
-
- data[idx+0]=E->key();
- data[idx+1]=E->get().type;
- data[idx+2]=E->get().pos;
- data[idx+3]=E->get().param1;
- data[idx+4]=E->get().param2;
-
- Array conns;
- conns.resize(E->get().connections.size()*3+E->get().defaults.size()*3);
- int idx2=0;
- for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
-
- conns[idx2+0]=F->key();
- conns[idx2+1]=F->get().id;
- conns[idx2+2]=F->get().slot;
- idx2+=3;
- }
- for(Map<int,Variant>::Element*F=E->get().defaults.front();F;F=F->next()) {
-
- conns[idx2+0]=SLOT_DEFAULT_VALUE;
- conns[idx2+1]=F->key();
- conns[idx2+2]=F->get();
- idx2+=3;
- }
-
- data[idx+5]=conns;
- idx+=6;
- }
- sh.push_back(data);
- }
-
- Dictionary data;
- data["shaders"]=sh;
- return data;
-}
-
-
-
-ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
-
- ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK);
- return shader[p_type].error;
-}
-
-int ShaderGraph::node_count(ShaderType p_which, int p_type)
-{
- int count=0;
- for (Map<int,Node>::Element *E=shader[p_which].node_map.front();E;E=E->next())
- if (E->get().type==p_type)
- count++;
- return count;
-}
-
-void ShaderGraph::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_update_shader"),&ShaderGraph::_update_shader);
-
- ClassDB::bind_method(D_METHOD("node_add","shader_type","node_type","id"),&ShaderGraph::node_add);
- ClassDB::bind_method(D_METHOD("node_remove","shader_type","id"),&ShaderGraph::node_remove);
- ClassDB::bind_method(D_METHOD("node_set_position","shader_type","id","position"),&ShaderGraph::node_set_position);
- ClassDB::bind_method(D_METHOD("node_get_position","shader_type","id"),&ShaderGraph::node_get_position);
-
- ClassDB::bind_method(D_METHOD("node_get_type","shader_type","id"),&ShaderGraph::node_get_type);
-
- ClassDB::bind_method(D_METHOD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
-
- ClassDB::bind_method(D_METHOD("default_set_value","shader_type","id","param_id","value"), &ShaderGraph::default_set_value);
- ClassDB::bind_method(D_METHOD("default_get_value","shader_type","id","param_id"), &ShaderGraph::default_get_value);
-
- ClassDB::bind_method(D_METHOD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
- ClassDB::bind_method(D_METHOD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_get_value);
-
- ClassDB::bind_method(D_METHOD("vec_const_node_set_value","shader_type","id","value"),&ShaderGraph::vec_const_node_set_value);
- ClassDB::bind_method(D_METHOD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_get_value);
-
- ClassDB::bind_method(D_METHOD("rgb_const_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_const_node_set_value);
- ClassDB::bind_method(D_METHOD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_get_value);
-
- ClassDB::bind_method(D_METHOD("xform_const_node_set_value","shader_type","id","value"),&ShaderGraph::xform_const_node_set_value);
- ClassDB::bind_method(D_METHOD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_get_value);
-
-
- //void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
-
- ClassDB::bind_method(D_METHOD("texture_node_set_filter_size","shader_type","id","filter_size"),&ShaderGraph::texture_node_set_filter_size);
- ClassDB::bind_method(D_METHOD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_get_filter_size);
-
- ClassDB::bind_method(D_METHOD("texture_node_set_filter_strength","shader_type","id","filter_strength"),&ShaderGraph::texture_node_set_filter_strength);
- ClassDB::bind_method(D_METHOD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_get_filter_strength);
-
- ClassDB::bind_method(D_METHOD("scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::scalar_op_node_set_op);
- ClassDB::bind_method(D_METHOD("scalar_op_node_get_op","shader_type","id"),&ShaderGraph::scalar_op_node_get_op);
-
- ClassDB::bind_method(D_METHOD("vec_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_op_node_set_op);
- ClassDB::bind_method(D_METHOD("vec_op_node_get_op","shader_type","id"),&ShaderGraph::vec_op_node_get_op);
-
- ClassDB::bind_method(D_METHOD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op);
- ClassDB::bind_method(D_METHOD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op);
-
- ClassDB::bind_method(D_METHOD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op);
- ClassDB::bind_method(D_METHOD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op);
-
-
- ClassDB::bind_method(D_METHOD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation);
- ClassDB::bind_method(D_METHOD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation);
-
- ClassDB::bind_method(D_METHOD("scalar_func_node_set_function","shader_type","id","func"),&ShaderGraph::scalar_func_node_set_function);
- ClassDB::bind_method(D_METHOD("scalar_func_node_get_function","shader_type","id"),&ShaderGraph::scalar_func_node_get_function);
-
- ClassDB::bind_method(D_METHOD("vec_func_node_set_function","shader_type","id","func"),&ShaderGraph::vec_func_node_set_function);
- ClassDB::bind_method(D_METHOD("vec_func_node_get_function","shader_type","id"),&ShaderGraph::vec_func_node_get_function);
-
- ClassDB::bind_method(D_METHOD("input_node_set_name","shader_type","id","name"),&ShaderGraph::input_node_set_name);
- ClassDB::bind_method(D_METHOD("input_node_get_name","shader_type","id"),&ShaderGraph::input_node_get_name);
-
- ClassDB::bind_method(D_METHOD("scalar_input_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_input_node_set_value);
- ClassDB::bind_method(D_METHOD("scalar_input_node_get_value","shader_type","id"),&ShaderGraph::scalar_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("vec_input_node_set_value","shader_type","id","value"),&ShaderGraph::vec_input_node_set_value);
- ClassDB::bind_method(D_METHOD("vec_input_node_get_value","shader_type","id"),&ShaderGraph::vec_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("rgb_input_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_input_node_set_value);
- ClassDB::bind_method(D_METHOD("rgb_input_node_get_value","shader_type","id"),&ShaderGraph::rgb_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("xform_input_node_set_value","shader_type","id","value"),&ShaderGraph::xform_input_node_set_value);
- ClassDB::bind_method(D_METHOD("xform_input_node_get_value","shader_type","id"),&ShaderGraph::xform_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("texture_input_node_set_value","shader_type","id","value"),&ShaderGraph::texture_input_node_set_value);
- ClassDB::bind_method(D_METHOD("texture_input_node_get_value","shader_type","id"),&ShaderGraph::texture_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("cubemap_input_node_set_value","shader_type","id","value"),&ShaderGraph::cubemap_input_node_set_value);
- ClassDB::bind_method(D_METHOD("cubemap_input_node_get_value","shader_type","id"),&ShaderGraph::cubemap_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text);
- ClassDB::bind_method(D_METHOD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text);
-
- ClassDB::bind_method(D_METHOD("color_ramp_node_set_ramp","shader_type","id","colors","offsets"),&ShaderGraph::color_ramp_node_set_ramp);
- ClassDB::bind_method(D_METHOD("color_ramp_node_get_colors","shader_type","id"),&ShaderGraph::color_ramp_node_get_colors);
- ClassDB::bind_method(D_METHOD("color_ramp_node_get_offsets","shader_type","id"),&ShaderGraph::color_ramp_node_get_offsets);
-
- ClassDB::bind_method(D_METHOD("curve_map_node_set_points","shader_type","id","points"),&ShaderGraph::curve_map_node_set_points);
- ClassDB::bind_method(D_METHOD("curve_map_node_get_points","shader_type","id"),&ShaderGraph::curve_map_node_get_points);
-
- ClassDB::bind_method(D_METHOD("connect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node);
- ClassDB::bind_method(D_METHOD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected);
- ClassDB::bind_method(D_METHOD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node);
- ClassDB::bind_method(D_METHOD("get_node_connections","shader_type"),&ShaderGraph::_get_connections);
-
- ClassDB::bind_method(D_METHOD("clear","shader_type"),&ShaderGraph::clear);
-
- ClassDB::bind_method(D_METHOD("node_set_state","shader_type","id","state"),&ShaderGraph::node_set_state);
- ClassDB::bind_method(D_METHOD("node_get_state","shader_type","id"),&ShaderGraph::node_get_state);
-
- 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 | PROPERTY_USAGE_INTERNAL), "_set_data","_get_data");
-
- //void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
-
-
- BIND_ENUM_CONSTANT( NODE_INPUT ); // all inputs (shader type dependent)
- BIND_ENUM_CONSTANT( NODE_SCALAR_CONST ); //scalar constant
- BIND_ENUM_CONSTANT( NODE_VEC_CONST ); //vec3 constant
- BIND_ENUM_CONSTANT( NODE_RGB_CONST ); //rgb constant (shows a color picker instead)
- BIND_ENUM_CONSTANT( NODE_XFORM_CONST ); // 4x4 matrix constant
- BIND_ENUM_CONSTANT( NODE_TIME ); // time in seconds
- BIND_ENUM_CONSTANT( NODE_SCREEN_TEX ); // screen texture sampler (takes UV) (only usable in fragment shader)
- BIND_ENUM_CONSTANT( NODE_SCALAR_OP ); // scalar vs scalar op (mul ); add ); div ); etc)
- BIND_ENUM_CONSTANT( NODE_VEC_OP ); // vec3 vs vec3 op (mul );ad );div );crossprod );etc)
- BIND_ENUM_CONSTANT( NODE_VEC_SCALAR_OP ); // vec3 vs scalar op (mul ); add ); div ); etc)
- BIND_ENUM_CONSTANT( NODE_RGB_OP ); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc.
- BIND_ENUM_CONSTANT( NODE_XFORM_MULT ); // mat4 x mat4
- BIND_ENUM_CONSTANT( NODE_XFORM_VEC_MULT ); // mat4 x vec3 mult (with no-translation option)
- BIND_ENUM_CONSTANT( NODE_XFORM_VEC_INV_MULT ); // mat4 x vec3 inverse mult (with no-translation option)
- BIND_ENUM_CONSTANT( NODE_SCALAR_FUNC ); // scalar function (sin ); cos ); etc)
- BIND_ENUM_CONSTANT( NODE_VEC_FUNC ); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc)
- BIND_ENUM_CONSTANT( NODE_VEC_LEN ); // vec3 length
- BIND_ENUM_CONSTANT( NODE_DOT_PROD ); // vec3 . vec3 (dot product -> scalar output)
- BIND_ENUM_CONSTANT( NODE_VEC_TO_SCALAR ); // 1 vec3 input ); 3 scalar outputs
- BIND_ENUM_CONSTANT( NODE_SCALAR_TO_VEC ); // 3 scalar input ); 1 vec3 output
- BIND_ENUM_CONSTANT( NODE_VEC_TO_XFORM ); // 3 vec input ); 1 xform output
- BIND_ENUM_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
- BIND_ENUM_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
- BIND_ENUM_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation (with optional curve)
- BIND_ENUM_CONSTANT( NODE_COLOR_RAMP );
- BIND_ENUM_CONSTANT( NODE_CURVE_MAP );
- BIND_ENUM_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material)
- BIND_ENUM_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material)
- BIND_ENUM_CONSTANT( NODE_DEFAULT_TEXTURE );
- BIND_ENUM_CONSTANT( NODE_OUTPUT ); // output (shader type dependent)
- BIND_ENUM_CONSTANT( NODE_COMMENT ); // comment
- BIND_ENUM_CONSTANT( NODE_TYPE_MAX );
-
- BIND_ENUM_CONSTANT( SLOT_TYPE_SCALAR );
- BIND_ENUM_CONSTANT( SLOT_TYPE_VEC );
- BIND_ENUM_CONSTANT( SLOT_TYPE_XFORM );
- BIND_ENUM_CONSTANT( SLOT_TYPE_TEXTURE );
- BIND_ENUM_CONSTANT( SLOT_MAX );
-
- BIND_ENUM_CONSTANT( SHADER_TYPE_VERTEX );
- BIND_ENUM_CONSTANT( SHADER_TYPE_FRAGMENT );
- BIND_ENUM_CONSTANT( SHADER_TYPE_LIGHT );
- BIND_ENUM_CONSTANT( SHADER_TYPE_MAX );
-
-
- BIND_ENUM_CONSTANT( SLOT_IN );
- BIND_ENUM_CONSTANT( SLOT_OUT );
-
- BIND_ENUM_CONSTANT( GRAPH_OK );
- BIND_ENUM_CONSTANT( GRAPH_ERROR_CYCLIC );
- BIND_ENUM_CONSTANT( GRAPH_ERROR_MISSING_CONNECTIONS );
-
- BIND_ENUM_CONSTANT( SCALAR_OP_ADD );
- BIND_ENUM_CONSTANT( SCALAR_OP_SUB );
- BIND_ENUM_CONSTANT( SCALAR_OP_MUL );
- BIND_ENUM_CONSTANT( SCALAR_OP_DIV );
- BIND_ENUM_CONSTANT( SCALAR_OP_MOD );
- BIND_ENUM_CONSTANT( SCALAR_OP_POW );
- BIND_ENUM_CONSTANT( SCALAR_OP_MAX );
- BIND_ENUM_CONSTANT( SCALAR_OP_MIN );
- BIND_ENUM_CONSTANT( SCALAR_OP_ATAN2 );
- BIND_ENUM_CONSTANT( SCALAR_MAX_OP );
-
- BIND_ENUM_CONSTANT( VEC_OP_ADD );
- BIND_ENUM_CONSTANT( VEC_OP_SUB );
- BIND_ENUM_CONSTANT( VEC_OP_MUL );
- BIND_ENUM_CONSTANT( VEC_OP_DIV );
- BIND_ENUM_CONSTANT( VEC_OP_MOD );
- BIND_ENUM_CONSTANT( VEC_OP_POW );
- BIND_ENUM_CONSTANT( VEC_OP_MAX );
- BIND_ENUM_CONSTANT( VEC_OP_MIN );
- BIND_ENUM_CONSTANT( VEC_OP_CROSS );
- BIND_ENUM_CONSTANT( VEC_MAX_OP );
-
- BIND_ENUM_CONSTANT( VEC_SCALAR_OP_MUL );
- BIND_ENUM_CONSTANT( VEC_SCALAR_OP_DIV );
- BIND_ENUM_CONSTANT( VEC_SCALAR_OP_POW );
- BIND_ENUM_CONSTANT( VEC_SCALAR_MAX_OP );
-
- BIND_ENUM_CONSTANT( RGB_OP_SCREEN );
- BIND_ENUM_CONSTANT( RGB_OP_DIFFERENCE );
- BIND_ENUM_CONSTANT( RGB_OP_DARKEN );
- BIND_ENUM_CONSTANT( RGB_OP_LIGHTEN );
- BIND_ENUM_CONSTANT( RGB_OP_OVERLAY );
- BIND_ENUM_CONSTANT( RGB_OP_DODGE );
- BIND_ENUM_CONSTANT( RGB_OP_BURN );
- BIND_ENUM_CONSTANT( RGB_OP_SOFT_LIGHT );
- BIND_ENUM_CONSTANT( RGB_OP_HARD_LIGHT );
- BIND_ENUM_CONSTANT( RGB_MAX_OP );
-
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SIN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_COS );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_TAN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ASIN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ACOS );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ATAN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SINH );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_COSH );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_TANH );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_LOG );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_EXP );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SQRT );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ABS );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SIGN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_FLOOR );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ROUND );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_CEIL );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_FRAC );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SATURATE );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_NEGATE );
- BIND_ENUM_CONSTANT( SCALAR_MAX_FUNC );
-
- BIND_ENUM_CONSTANT( VEC_FUNC_NORMALIZE );
- BIND_ENUM_CONSTANT( VEC_FUNC_SATURATE );
- BIND_ENUM_CONSTANT( VEC_FUNC_NEGATE );
- BIND_ENUM_CONSTANT( VEC_FUNC_RECIPROCAL );
- BIND_ENUM_CONSTANT( VEC_FUNC_RGB2HSV );
- BIND_ENUM_CONSTANT( VEC_FUNC_HSV2RGB );
- BIND_ENUM_CONSTANT( VEC_MAX_FUNC );
-
- ADD_SIGNAL(MethodInfo("updated"));
-}
-
-
-String ShaderGraph::_find_unique_name(const String& p_base) {
-
-
-
- int idx=1;
- while(true) {
- String tocmp=p_base;
- if (idx>1) {
- tocmp+="_"+itos(idx);
- }
- bool valid=true;
- for(int i=0;i<3;i++) {
- if (!valid)
- break;
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
- if (E->get().type!=NODE_SCALAR_INPUT && E->get().type!=NODE_VEC_INPUT && E->get().type==NODE_RGB_INPUT && E->get().type==NODE_XFORM_INPUT && E->get().type==NODE_TEXTURE_INPUT && E->get().type==NODE_CUBEMAP_INPUT)
- continue;
- String name = E->get().param1;
- if (name==tocmp) {
- valid=false;
- break;
- }
-
- }
- }
-
- if (!valid) {
- idx++;
- continue;
- }
- return tocmp;
- }
- return String();
-}
-
-void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(p_id==0);
- ERR_FAIL_COND(p_node_type==NODE_OUTPUT); //can't create output
- ERR_FAIL_COND( shader[p_type].node_map.has(p_id ) );
- ERR_FAIL_INDEX( p_node_type, NODE_TYPE_MAX );
- Node node;
-
- if (p_node_type==NODE_INPUT) {
- //see if it already exists
- for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- if (E->get().type==NODE_INPUT) {
- ERR_EXPLAIN("Only one input node can be added to the graph.");
- ERR_FAIL_COND(E->get().type==NODE_INPUT);
- }
- }
- }
- node.type=p_node_type;
- node.id=p_id;
-
- switch(p_node_type) {
- case NODE_INPUT: {} break; // all inputs (shader type dependent)
- case NODE_SCALAR_CONST: { node.param1=0;} break; //scalar constant
- case NODE_VEC_CONST: {node.param1=Vector3();} break; //vec3 constant
- case NODE_RGB_CONST: {node.param1=Color();} break; //rgb constant (shows a color picker instead)
- case NODE_XFORM_CONST: {node.param1=Transform();} break; // 4x4 matrix constant
- case NODE_TIME: {} break; // time in seconds
- case NODE_SCREEN_TEX: {Array arr; arr.push_back(0); arr.push_back(0); node.param2=arr;} break; // screen texture sampler (takes UV) (only usable in fragment shader)
- case NODE_SCALAR_OP: {node.param1=SCALAR_OP_ADD;} break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
- case NODE_VEC_OP: {node.param1=VEC_OP_ADD;} break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc)
- case NODE_VEC_SCALAR_OP: {node.param1=VEC_SCALAR_OP_MUL;} break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
- case NODE_RGB_OP: {node.param1=RGB_OP_SCREEN;} break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc.
- case NODE_XFORM_MULT: {} break; // mat4 x mat4
- case NODE_XFORM_VEC_MULT: {} break; // mat4 x vec3 mult (with no-translation option)
- case NODE_XFORM_VEC_INV_MULT: {} break; // mat4 x vec3 inverse mult (with no-translation option)
- case NODE_SCALAR_FUNC: {node.param1=SCALAR_FUNC_SIN;} break; // scalar function (sin: {} break; cos: {} break; etc)
- case NODE_VEC_FUNC: {node.param1=VEC_FUNC_NORMALIZE;} break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc)
- case NODE_VEC_LEN: {} break; // vec3 length
- case NODE_DOT_PROD: {} break; // vec3 . vec3 (dot product -> scalar output)
- case NODE_VEC_TO_SCALAR: {} break; // 1 vec3 input: {} break; 3 scalar outputs
- case NODE_SCALAR_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
- case NODE_VEC_TO_XFORM: {} break; // 3 scalar input: {} break; 1 vec3 output
- case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
- case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
- case NODE_VEC_INTERP: {} break; // vec3 interpolation (with optional curve)
- case NODE_COLOR_RAMP: { node.param1=PoolVector<Color>(); node.param2=PoolVector<real_t>();} break; // vec3 interpolation (with optional curve)
- case NODE_CURVE_MAP: { node.param1=PoolVector<Vector2>();} break; // vec3 interpolation (with optional curve)
- case NODE_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
- case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
- case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
- case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
- case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
- case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
- case NODE_DEFAULT_TEXTURE: {}; break;
- case NODE_OUTPUT: {} break; // output (shader type dependent)
- case NODE_COMMENT: {} break; // comment
- case NODE_TYPE_MAX: {};
- }
-
- shader[p_type].node_map[p_id]=node;
- _request_update();
-}
-
-void ShaderGraph::node_set_position(ShaderType p_type,int p_id, const Vector2& p_pos) {
- ERR_FAIL_INDEX(p_type,3);
-
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- shader[p_type].node_map[p_id].pos=p_pos;
- _request_update();
-
-}
-Vector2 ShaderGraph::node_get_position(ShaderType p_type,int p_id) const {
- ERR_FAIL_INDEX_V(p_type,3,Vector2());
-
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector2());
- return shader[p_type].node_map[p_id].pos;
-}
-
-
-void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
-
- ERR_FAIL_COND(p_id==0);
- ERR_FAIL_INDEX(p_type,3);
-
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
-
- //erase connections associated with node
- for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- if (E->key()==p_id)
- continue; //no self
-
- for (Map<int,SourceSlot>::Element *F=E->get().connections.front();F;) {
- Map<int,SourceSlot>::Element *N=F->next();
-
- if (F->get().id==p_id) {
- E->get().connections.erase(F);
- }
-
- F=N;
- }
- }
-
- shader[p_type].node_map.erase(p_id);
-
- _request_update();
-
-}
-
-
-
-void ShaderGraph::get_node_list(ShaderType p_type,List<int> *p_node_list) const {
-
- ERR_FAIL_INDEX(p_type,3);
-
- Map<int,Node>::Element *E = shader[p_type].node_map.front();
-
- while(E) {
-
- p_node_list->push_back(E->key());
- E=E->next();
- }
-}
-
-
-ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const {
-
- ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX);
-
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),NODE_TYPE_MAX);
- return shader[p_type].node_map[p_id].type;
-}
-
-
-Error ShaderGraph::connect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- ERR_FAIL_INDEX_V(p_type,3,ERR_INVALID_PARAMETER);
-
- ERR_FAIL_COND_V(p_src_id==p_dst_id, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
- NodeType type_src=shader[p_type].node_map[p_src_id].type;
- NodeType type_dst=shader[p_type].node_map[p_dst_id].type;
- ERR_FAIL_INDEX_V( p_src_slot, get_node_output_slot_count(get_mode(),p_type,type_src), ERR_INVALID_PARAMETER );
- ERR_FAIL_INDEX_V( p_dst_slot, get_node_input_slot_count(get_mode(),p_type,type_dst), ERR_INVALID_PARAMETER );
- ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(),p_type,type_src,p_src_slot) != get_node_input_slot_type(get_mode(),p_type,type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
-
-
- SourceSlot ts;
- ts.id=p_src_id;
- ts.slot=p_src_slot;
- shader[p_type].node_map[p_dst_id].connections[p_dst_slot]=ts;
- _request_update();
-
- return OK;
-}
-
-bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
-
- ERR_FAIL_INDEX_V(p_type,3,false);
-
- SourceSlot ts;
- ts.id=p_src_id;
- ts.slot=p_src_slot;
- return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
- shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts;
-}
-
-void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- ERR_FAIL_INDEX(p_type,3);
-
- SourceSlot ts;
- ts.id=p_src_id;
- ts.slot=p_src_slot;
- if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
- shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts) {
- shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot);
-
- }
- _request_update();
-
-}
-
-void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_connections) const {
-
- ERR_FAIL_INDEX(p_type,3);
-
- for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
-
- Connection c;
- c.dst_id=E->key();
- c.dst_slot=F->key();
- c.src_id=F->get().id;
- c.src_slot=F->get().slot;
- p_connections->push_back(c);
- }
- }
-}
-
-bool ShaderGraph::is_slot_connected(ShaderGraph::ShaderType p_type, int p_dst_id, int slot_id)
-{
- for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
-
- if (p_dst_id == E->key() && slot_id==F->key())
- return true;
- }
- }
- return false;
-}
-
-
-void ShaderGraph::clear(ShaderType p_type) {
-
- ERR_FAIL_INDEX(p_type,3);
- shader[p_type].node_map.clear();
- Node out;
- out.pos=Vector2(300,300);
- out.type=NODE_OUTPUT;
- shader[p_type].node_map.insert(0,out);
-
- _request_update();
-
-}
-
-
-void ShaderGraph::scalar_const_node_set_value(ShaderType p_type,int p_id,float p_value) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_CONST);
- n.param1=p_value;
- _request_update();
-
-}
-
-float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_CONST,0);
- return n.param1;
-}
-
-void ShaderGraph::vec_const_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_CONST);
- n.param1=p_value;
- _request_update();
-
-
-}
-Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Vector3());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_CONST,Vector3());
- return n.param1;
-
-}
-
-void ShaderGraph::rgb_const_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_RGB_CONST);
- n.param1=p_value;
- _request_update();
-
-}
-Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Color());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_RGB_CONST,Color());
- return n.param1;
-
-}
-
-void ShaderGraph::xform_const_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_XFORM_CONST);
- n.param1=p_value;
- _request_update();
-
-}
-Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Transform());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_XFORM_CONST,Transform());
- return n.param1;
-
-}
-
-void ShaderGraph::texture_node_set_filter_size(ShaderType p_type,int p_id,int p_size){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
- Array arr = n.param2;
- arr[0]=p_size;
- n.param2=arr;
- _request_update();
-
-}
-int ShaderGraph::texture_node_get_filter_size(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
- Array arr = n.param2;
- return arr[0];
-
-}
-
-void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type,float p_id,float p_strength){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
- Array arr = n.param2;
- arr[1]=p_strength;
- n.param2=arr;
- _request_update();
-
-}
-float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
- Array arr = n.param2;
- return arr[1];
-}
-
-void ShaderGraph::duplicate_nodes(ShaderType p_which, List<int> &p_nodes)
-{
- //Create new node IDs
- Map<int,int> duplicates = Map<int,int>();
- int i=1;
- for(List<int>::Element *E=p_nodes.front();E; E=E->next()) {
- while (shader[p_which].node_map.has(i))
- i++;
- duplicates.insert(E->get(), i);
- i++;
- }
-
- for(List<int>::Element *E = p_nodes.front();E; E=E->next()) {
-
- const Node &n=shader[p_which].node_map[E->get()];
- Node nn=n;
- nn.id=duplicates.find(n.id)->get();
- nn.pos += Vector2(0,100);
- for (Map<int,SourceSlot>::Element *C=nn.connections.front();C;C=C->next()) {
- SourceSlot &c=C->get();
- if (p_nodes.find(c.id))
- c.id=duplicates.find(c.id)->get();
- }
- shader[p_which].node_map[nn.id]=nn;
- }
- _request_update();
-}
-
-List<int> ShaderGraph::generate_ids(ShaderType p_type, int count)
-{
- List<int> ids = List<int>();
- int i=1;
- while (ids.size() < count) {
- while (shader[p_type].node_map.has(i))
- i++;
- ids.push_back(i);
- i++;
- }
- return ids;
-}
-
-
-void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_OP);
- n.param1=p_op;
- _request_update();
-
-}
-ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_OP,SCALAR_MAX_OP);
- int op = n.param1;
- return ScalarOp(op);
-
-}
-
-
-void ShaderGraph::vec_op_node_set_op(ShaderType p_type,float p_id,VecOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_OP);
- n.param1=p_op;
- _request_update();
-
-}
-ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_OP,VEC_MAX_OP);
- int op = n.param1;
- return VecOp(op);
-
-}
-
-
-void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type,float p_id,VecScalarOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_SCALAR_OP);
- n.param1=p_op;
- _request_update();
-
-}
-ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,VEC_SCALAR_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_SCALAR_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_SCALAR_OP,VEC_SCALAR_MAX_OP);
- int op = n.param1;
- return VecScalarOp(op);
-
-}
-
-void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_RGB_OP);
- n.param1=p_op;
-
- _request_update();
-
-}
-ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,RGB_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),RGB_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,RGB_MAX_OP);
- int op = n.param1;
- return RGBOp(op);
-
-}
-
-
-void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT);
- n.param1=p_no_translation;
- _request_update();
-
-}
-bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,false);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),false);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT,false);
- return n.param1;
-
-}
-
-void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,ScalarFunc p_func){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC);
- int func = p_func;
- ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
- n.param1=func;
- _request_update();
-
-}
-ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_FUNC);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_FUNC);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_FUNC,SCALAR_MAX_FUNC);
- int func = n.param1;
- return ScalarFunc(func);
-}
-
-void ShaderGraph::default_set_value(ShaderGraph::ShaderType p_which, int p_id, int p_param, const Variant &p_value)
-{
- ERR_FAIL_INDEX(p_which,3);
- ERR_FAIL_COND(!shader[p_which].node_map.has(p_id));
- Node& n = shader[p_which].node_map[p_id];
- if(p_value.get_type()==Variant::NIL)
- n.defaults.erase(n.defaults.find(p_param));
- else
- n.defaults[p_param]=p_value;
-
- _request_update();
-
-}
-
-Variant ShaderGraph::default_get_value(ShaderGraph::ShaderType p_which, int p_id, int p_param)
-{
- ERR_FAIL_INDEX_V(p_which,3,Variant());
- ERR_FAIL_COND_V(!shader[p_which].node_map.has(p_id),Variant());
- const Node& n = shader[p_which].node_map[p_id];
-
- if (!n.defaults.has(p_param))
- return Variant();
- return n.defaults[p_param];
-}
-
-
-
-void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_FUNC);
- int func = p_func;
- ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
- n.param1=func;
-
- _request_update();
-
-}
-ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_FUNC);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_FUNC);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_FUNC,VEC_MAX_FUNC);
- int func = n.param1;
- return VecFunc(func);
-}
-
-void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type,int p_id,const PoolVector<Color>& p_colors, const PoolVector<real_t>& p_offsets){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_colors;
- n.param2=p_offsets;
- _request_update();
-
-}
-
-PoolVector<Color> ShaderGraph::color_ramp_node_get_colors(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,PoolVector<Color>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),PoolVector<Color>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
-
-
-}
-
-PoolVector<real_t> ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,PoolVector<real_t>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),PoolVector<real_t>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param2;
-
-}
-
-
-void ShaderGraph::curve_map_node_set_points(ShaderType p_type,int p_id,const PoolVector<Vector2>& p_points) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_points;
- _request_update();
-
-}
-
-PoolVector<Vector2> ShaderGraph::curve_map_node_get_points(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,PoolVector<Vector2>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),PoolVector<Vector2>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
-
-}
-
-
-
-void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- ERR_FAIL_COND(!p_name.is_valid_identifier());
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT);
-
- n.param1="";
- n.param1=_find_unique_name(p_name);
- _request_update();
-
-}
-String ShaderGraph::input_node_get_name(ShaderType p_type,int p_id){
-
- ERR_FAIL_INDEX_V(p_type,3,String());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT,String());
- return n.param1;
-}
-
-
-void ShaderGraph::scalar_input_node_set_value(ShaderType p_type,int p_id,float p_value) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT);
- n.param2=p_value;
- _request_update();
-
-}
-
-float ShaderGraph::scalar_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT,0);
-
- return n.param2;
-}
-
-void ShaderGraph::vec_input_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_INPUT);
-
- n.param2=p_value;
- _request_update();
-
-}
-Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Vector3());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_INPUT,Vector3());
- return n.param2;
-}
-
-void ShaderGraph::rgb_input_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_RGB_INPUT);
- n.param2=p_value;
- _request_update();
-
-}
-Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Color());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_RGB_INPUT,Color());
- return n.param2;
-}
-
-void ShaderGraph::xform_input_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_XFORM_INPUT);
- n.param2=p_value;
- _request_update();
-
-}
-Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Transform());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_XFORM_INPUT,Transform());
- return n.param2;
-}
-
-
-void ShaderGraph::texture_input_node_set_value(ShaderType p_type,int p_id,const Ref<Texture>& p_texture) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT);
- n.param2=p_texture;
- _request_update();
-
-}
-
-Ref<Texture> ShaderGraph::texture_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Ref<Texture>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<Texture>());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT,Ref<Texture>());
- return n.param2;
-}
-
-void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type,int p_id,const Ref<CubeMap>& p_cubemap){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_CUBEMAP_INPUT);
- n.param2=p_cubemap;
- _request_update();
-
-}
-
-Ref<CubeMap> ShaderGraph::cubemap_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Ref<CubeMap>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<CubeMap>());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_CUBEMAP_INPUT,Ref<CubeMap>());
- return n.param2;
-
-}
-
-
-void ShaderGraph::comment_node_set_text(ShaderType p_type,int p_id,const String& p_comment) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_COMMENT);
- n.param1=p_comment;
-
-}
-
-String ShaderGraph::comment_node_get_text(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,String());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_COMMENT,String());
- return n.param1;
-
-}
-
-void ShaderGraph::_request_update() {
-
- if (_pending_update_shader)
- return;
-
- _pending_update_shader=true;
- call_deferred("_update_shader");
-
-}
-
-Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
-
- ERR_FAIL_INDEX_V(p_type,3,Variant());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Variant());
- const Node& n = shader[p_type].node_map[p_id];
- Dictionary s;
- s["position"]=n.pos;
- s["param1"]=n.param1;
- s["param2"]=n.param2;
- Array keys;
- for (Map<int,Variant>::Element *E=n.defaults.front();E;E=E->next()) {
- keys.append(E->key());
- s[E->key()]=E->get();
- }
- s["default_keys"]=keys;
- return s;
-
-}
-void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_state) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- Dictionary d = p_state;
- ERR_FAIL_COND(!d.has("position"));
- ERR_FAIL_COND(!d.has("param1"));
- ERR_FAIL_COND(!d.has("param2"));
- ERR_FAIL_COND(!d.has("default_keys"));
-
- n.pos=d["position"];
- n.param1=d["param1"];
- n.param2=d["param2"];
- Array keys = d["default_keys"];
- for(int i=0;i<keys.size();i++) {
- n.defaults[keys[i]]=d[keys[i]];
- }
-}
-
-ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
-
- //shader = VisualServer::get_singleton()->shader_create();
- _pending_update_shader=false;
-
- Node input;
- input.id=1;
- input.pos=Vector2(50,40);
- input.type=NODE_INPUT;
-
- Node output;
- output.id=0;
- output.pos=Vector2(350,40);
- output.type=NODE_OUTPUT;
-
- for(int i=0;i<3;i++) {
-
- shader[i].node_map.insert(0,output);
- shader[i].node_map.insert(1,input);
- }
-}
-
-ShaderGraph::~ShaderGraph() {
-
- //VisualServer::get_singleton()->free(shader);
-}
-
-
-const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
- //material vertex in
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","SRC_VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","SRC_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","SRC_TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"BinormalF","SRC_BINORMALF","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","SRC_COLOR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","SRC_ALPHA","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","SRC_UV2","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ModelviewMatrix","MODELVIEW_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InstanceID","INSTANCE_ID","",SLOT_TYPE_SCALAR,SLOT_IN},
-
- //material vertex out
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"SpecExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //pixel vertex in
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","vec3(UV2,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- //pixel vertex out
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Discard","DISCARD",">0.5",SLOT_TYPE_SCALAR,SLOT_OUT},
- //light in
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDir","LIGHT_DIR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDiffuse","LIGHT_DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightSpecular","LIGHT_SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"EyeVec","EYE_VEC","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Diffuse","DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"SpecExp","SPECULAR_EXP","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN},
- //light out
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Shadow", "SHADOW", "",SLOT_TYPE_VEC, SLOT_OUT },
- //canvas item vertex in
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","vec3(SRC_VERTEX,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ExtraMatrix","EXTRA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- //canvas item vertex out
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","VERTEX",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //canvas item fragment in
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Position","POSITION","",SLOT_TYPE_VEC,SLOT_IN},
- //canvas item fragment out
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //canvas item light in
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightColor","LIGHT_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightAlpha","LIGHT_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightHeight","LIGHT_HEIGHT","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowColor","LIGHT_SHADOW.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowAlpha","LIGHT_SHADOW.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Position","POSITION","",SLOT_TYPE_VEC,SLOT_IN},
- //canvas item light out
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightColor","LIGHT.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightAlpha","LIGHT.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowColor","SHADOW.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowAlpha","SHADOW.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //end
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
-
-
-
-};
-
-void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_type==iop->shader_type) {
-
- SlotInfo si;
- si.dir=iop->dir;
- si.name=iop->name;
- si.type=iop->slot_type;
- r_slots->push_back(si);
- }
- iop++;
- }
-}
-
-
-const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
-
- {NODE_SCALAR_CONST,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, //scalar constant
- {NODE_VEC_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //vec3 constant
- {NODE_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, //rgb constant (shows a color picker instead)
- {NODE_XFORM_CONST,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // 4x4 matrix constant
- {NODE_TIME,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // time in seconds
- {NODE_SCREEN_TEX,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // screen texture sampler (takes UV) (only usable in fragment shader)
- {NODE_SCALAR_OP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_SCALAR_OP,{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4
- {NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option)
- {NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
- {NODE_SCALAR_FUNC,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_FUNC,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_LEN,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 length
- {NODE_DOT_PROD,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 . vec3 (dot product -> scalar output)
- {NODE_VEC_TO_SCALAR,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR}}, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs
- {NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output
- {NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve)
- {NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation (with optional curve)
- {NODE_COLOR_RAMP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
- {NODE_CURVE_MAP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
- {NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material)
- {NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material)
- {NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // color uniform (assignable in material)
- {NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material)
- {NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material)
- {NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
- {NODE_DEFAULT_TEXTURE,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
- {NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
- {NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}}
-};
-
-int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type) {
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_OUT)
- pc++;
- }
- iop++;
- }
- return pc;
- } else if (p_type==NODE_VEC_TO_XFORM){
- return 4;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return 1;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- int pc=0;
- for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
- if (nsi->ins[i]==SLOT_MAX)
- break;
- pc++;
- }
- return pc;
- }
-
- nsi++;
- }
-
- return 0;
-
- }
-}
-
-int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type){
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_IN)
- pc++;
- }
- iop++;
- }
- return pc;
- } else if (p_type==NODE_VEC_TO_XFORM){
- return 1;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return 4;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- int pc=0;
- for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
- if (nsi->outs[i]==SLOT_MAX)
- break;
- pc++;
- }
- return pc;
- }
-
- nsi++;
- }
-
- return 0;
-
- }
-}
-ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_OUT) {
- if (pc==p_idx)
- return iop->slot_type;
- pc++;
- }
- }
- iop++;
- }
- ERR_FAIL_V(SLOT_MAX);
- } else if (p_type==NODE_VEC_TO_XFORM){
- return SLOT_TYPE_VEC;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return SLOT_TYPE_XFORM;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
-
- if (nsi->ins[i]==SLOT_MAX)
- break;
- if (i==p_idx)
- return nsi->ins[i];
- }
- }
-
- nsi++;
- }
-
- ERR_FAIL_V(SLOT_MAX);
-
- }
-}
-ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_IN) {
- if (pc==p_idx)
- return iop->slot_type;
- pc++;
- }
- }
- iop++;
- }
- ERR_FAIL_V(SLOT_MAX);
- } else if (p_type==NODE_VEC_TO_XFORM){
- return SLOT_TYPE_XFORM;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return SLOT_TYPE_VEC;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
- if (nsi->outs[i]==SLOT_MAX)
- break;
- if (i==p_idx)
- return nsi->outs[i];
- }
- }
-
- nsi++;
- }
-
- ERR_FAIL_V(SLOT_MAX);
- }
-}
-
-
-
-
-
-void ShaderGraph::_update_shader() {
-
-
- String code[3];
-
- List<StringName> names;
- get_default_texture_param_list(&names);
-
- for (List<StringName>::Element *E=names.front();E;E=E->next()) {
-
- set_default_texture_param(E->get(),Ref<Texture>());
- }
-
-
- for(int i=0;i<3;i++) {
-
- int idx=0;
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
-
- E->get().sort_order=idx++;
- }
- //simple method for graph solving using bubblesort derived algorithm
- int iters=0;
- int iter_max=shader[i].node_map.size()*shader[i].node_map.size();
-
- while(true) {
- if (iters>iter_max)
- break;
-
- int swaps=0;
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
-
- for(Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
-
- //this is kinda slow, could be sped up
- Map<int,Node>::Element *G = shader[i].node_map.find(F->get().id);
- ERR_FAIL_COND(!G);
- if (G->get().sort_order > E->get().sort_order) {
-
- SWAP(G->get().sort_order,E->get().sort_order);
- swaps++;
- }
- }
- }
-
- iters++;
- if (swaps==0) {
- iters=0;
- break;
- }
- }
-
- if (iters>0) {
-
- shader[i].error=GRAPH_ERROR_CYCLIC;
- continue;
- }
-
- Vector<Node*> order;
- order.resize(shader[i].node_map.size());
-
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
-
- order[E->get().sort_order]=&E->get();
- }
-
- //generate code for the ordered graph
- bool failed=false;
-
- if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
- code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);\n";
- code[i]+="float ALPHA_OUT=0;\n";
- }
-
-
- Map<String,String> inputs_xlate;
- Map<String,String> input_names_xlate;
- Set<String> inputs_used;
-
- for(int j=0;j<order.size();j++) {
-
- Node *n=order[j];
- if (n->type==NODE_INPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int idx=0;
- while(iop->name) {
- if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_IN==iop->dir) {
-
- const char *typestr[4]={"float","vec3","mat4","texture"};
-
- String vname=("nd"+itos(n->id)+"sl"+itos(idx));
- inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n";
- input_names_xlate[vname]=iop->variable;
- idx++;
- }
- iop++;
- }
-
- } else if (n->type==NODE_OUTPUT) {
-
-
- bool use_alpha=false;
- const InOutParamInfo* iop = &inout_param_info[0];
- int idx=0;
- while(iop->name) {
- if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_OUT==iop->dir) {
-
- if (n->connections.has(idx)) {
- String iname=("nd"+itos(n->connections[idx].id)+"sl"+itos(n->connections[idx].slot));
- if (node_get_type(ShaderType(i),n->connections[idx].id)==NODE_INPUT)
- inputs_used.insert(iname);
- code[i]+=String(iop->variable)+"="+iname+String(iop->postfix)+";\n";
- if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha")
- use_alpha=true;
- }
- idx++;
- }
- iop++;
- }
-
- if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
-
- if (use_alpha) {
- code[i]+="DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n";
- } else {
- code[i]+="DIFFUSE=DIFFUSE_OUT;\n";
- }
- }
-
- } else {
- Vector<String> inputs;
- int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
- for(int k=0;k<max;k++) {
- String iname;
- if (!n->connections.has(k)) {
- iname="nd"+itos(n->id)+"sl"+itos(k)+"def";
- } else {
- iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
- if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
- inputs_used.insert(iname);
- }
-
- }
- inputs.push_back(iname);
- }
-
- if (failed)
- break;
-
- if (n->type==NODE_TEXTURE_INPUT || n->type==NODE_CUBEMAP_INPUT) {
-
- set_default_texture_param(n->param1,n->param2);
-
- }
- _add_node_code(ShaderType(i),n,inputs,code[i]);
- }
-
- }
-
- if (failed)
- continue;
-
-
- for(Set<String>::Element *E=inputs_used.front();E;E=E->next()) {
-
- ERR_CONTINUE( !inputs_xlate.has(E->get()));
- code[i]=inputs_xlate[E->get()]+code[i];
- String name=input_names_xlate[E->get()];
-
- if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_MATERIAL) {
- if (name==("SRC_COLOR"))
- code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
- if (name==("SRC_ALPHA"))
- code[i]="float SRC_ALPHA=COLOR.a;\n"+code[i];
- if (name==("SRC_UV"))
- code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
- if (name==("SRC_UV2"))
- code[i]="float SRC_UV2=vec3(UV2,0);\n"+code[i];
- } else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
- if (name==("IN_NORMAL"))
- code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i];
- } else if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_CANVAS_ITEM) {
- if (name==("SRC_COLOR"))
- code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
- if (name==("SRC_UV"))
- code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
- }
-
- }
-
-
-
- shader[i].error=GRAPH_OK;
-
- }
-
- bool all_ok=true;
- for(int i=0;i<3;i++) {
- if (shader[i].error!=GRAPH_OK)
- all_ok=false;
- }
-
- /*print_line("VERTEX: \n"+code[0]);
- print_line("FRAGMENT: \n"+code[1]);
- print_line("LIGHT: \n"+code[2]);*/
-
- if (all_ok) {
- set_code(code[0],code[1],code[2]);
- }
- //do shader here
-
- _pending_update_shader=false;
- emit_signal(SceneStringNames::get_singleton()->updated);
-}
-
-void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds) {
-
- float geometry[4][4];
- float tmp1[4][4];
- float tmp2[4][4];
- float deltas[4][4];
- double x, dx, dx2, dx3;
- double y, dy, dy2, dy3;
- double d, d2, d3;
- int lastx, lasty;
- int newx, newy;
- int ntimes;
- int i,j;
-
- int xmax=255;
- int ymax=255;
-
- /* construct the geometry matrix from the segment */
- for (i = 0; i < 4; i++) {
- geometry[i][2] = 0;
- geometry[i][3] = 0;
- }
-
- geometry[0][0] = (p_a[0] * xmax);
- geometry[1][0] = (p_b[0] * xmax);
- geometry[2][0] = (p_c[0] * xmax);
- geometry[3][0] = (p_d[0] * xmax);
-
- geometry[0][1] = (p_a[1] * ymax);
- geometry[1][1] = (p_b[1] * ymax);
- geometry[2][1] = (p_c[1] * ymax);
- geometry[3][1] = (p_d[1] * ymax);
-
- /* subdivide the curve ntimes (1000) times */
- ntimes = 4 * xmax;
- /* ntimes can be adjusted to give a finer or coarser curve */
- d = 1.0 / ntimes;
- d2 = d * d;
- d3 = d * d * d;
-
- /* construct a temporary matrix for determining the forward differencing deltas */
- tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
- tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
- tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
- tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
-
- /* compose the basis and geometry matrices */
-
- static const float CR_basis[4][4] = {
- { -0.5, 1.5, -1.5, 0.5 },
- { 1.0, -2.5, 2.0, -0.5 },
- { -0.5, 0.0, 0.5, 0.0 },
- { 0.0, 1.0, 0.0, 0.0 },
- };
-
- for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
- {
- tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
- CR_basis[i][1] * geometry[1][j] +
- CR_basis[i][2] * geometry[2][j] +
- CR_basis[i][3] * geometry[3][j]);
- }
- }
- /* compose the above results to get the deltas matrix */
-
- for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
- {
- deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
- tmp2[i][1] * tmp1[1][j] +
- tmp2[i][2] * tmp1[2][j] +
- tmp2[i][3] * tmp1[3][j]);
- }
- }
-
-
- /* extract the x deltas */
- x = deltas[0][0];
- dx = deltas[1][0];
- dx2 = deltas[2][0];
- dx3 = deltas[3][0];
-
- /* extract the y deltas */
- y = deltas[0][1];
- dy = deltas[1][1];
- dy2 = deltas[2][1];
- dy3 = deltas[3][1];
-
-
- lastx = CLAMP (x, 0, xmax);
- lasty = CLAMP (y, 0, ymax);
-
- p_heights[lastx] = lasty;
- p_useds[lastx] = true;
-
- /* loop over the curve */
- for (i = 0; i < ntimes; i++)
- {
- /* increment the x values */
- x += dx;
- dx += dx2;
- dx2 += dx3;
-
- /* increment the y values */
- y += dy;
- dy += dy2;
- dy2 += dy3;
-
- newx = CLAMP ((Math::round (x)), 0, xmax);
- newy = CLAMP ((Math::round (y)), 0, ymax);
-
- /* if this point is different than the last one...then draw it */
- if ((lastx != newx) || (lasty != newy))
- {
- p_useds[newx]=true;
- p_heights[newx]=newy;
- }
-
- lastx = newx;
- lasty = newy;
- }
-}
-
-
-void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
-
-
- const char *typestr[4]={"float","vec3","mat4","texture"};
-#define OUTNAME(id, slot) (String(typestr[get_node_output_slot_type(get_mode(), p_type, p_node->type, slot)]) + " " + ("nd" + itos(id) + "sl" + itos(slot)))
-#define OUTVAR(id, slot) ("nd" + itos(id) + "sl" + itos(slot))
-#define DEF_VEC(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- Vector3 v = p_node->defaults[slot]; \
- code += String(typestr[1]) + " " + p_inputs[slot] + "=vec3(" + v + ");\n"; \
- }
-#define DEF_SCALAR(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- double v = p_node->defaults[slot]; \
- code += String(typestr[0]) + " " + p_inputs[slot] + "=" + rtos(v) + ";\n"; \
- }
-#define DEF_COLOR(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- Color col = p_node->defaults[slot]; \
- code += String(typestr[1]) + " " + p_inputs[slot] + "=vec3(" + rtos(col.r) + "," + rtos(col.g) + "," + rtos(col.b) + ");\n"; \
- }
-#define DEF_MATRIX(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- Transform xf = p_node->defaults[slot]; \
- code += String(typestr[2]) + " " + p_inputs[slot] + "=mat4(\n"; \
- code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(0).x) + "," + rtos(xf.basis.get_axis(0).y) + "," + rtos(xf.basis.get_axis(0).z) + "),0),\n"; \
- code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(1).x) + "," + rtos(xf.basis.get_axis(1).y) + "," + rtos(xf.basis.get_axis(1).z) + "),0),\n"; \
- code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(2).x) + "," + rtos(xf.basis.get_axis(2).y) + "," + rtos(xf.basis.get_axis(2).z) + "),0),\n"; \
- code += "\tvec4(vec3(" + rtos(xf.origin.x) + "," + rtos(xf.origin.y) + "," + rtos(xf.origin.z) + "),1)\n"; \
- code += ");\n"; \
- }
-
- switch(p_node->type) {
-
- case NODE_INPUT: {
-
-
- }break;
- case NODE_SCALAR_CONST: {
-
- double scalar = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"="+rtos(scalar)+";\n";
- }break;
- case NODE_VEC_CONST: {
- Vector3 vec = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(vec.x)+","+rtos(vec.y)+","+rtos(vec.z)+");\n";
- }break;
- case NODE_RGB_CONST: {
- Color col = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";
- code+=OUTNAME(p_node->id,1)+"="+rtos(col.a)+";\n";
- }break;
- case NODE_XFORM_CONST: {
-
- Transform xf = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"=mat4(\n";
- code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";
- code+=");";
-
- }break;
- case NODE_TIME: {
- code+=OUTNAME(p_node->id,0)+"=TIME;\n";
- }break;
- case NODE_SCREEN_TEX: {
- DEF_VEC(0);
- code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+".xy);\n";
- }break;
- case NODE_SCALAR_OP: {
- DEF_SCALAR(0);
- DEF_SCALAR(1);
- int op = p_node->param1;
- String optxt;
- switch(op) {
-
- case SCALAR_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
- case SCALAR_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
- case SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
- case SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
- case SCALAR_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_ATAN2: optxt = "atan2("+p_inputs[0]+","+p_inputs[1]+");"; break;
-
- }
- code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
-
- }break;
- case NODE_VEC_OP: {
- DEF_VEC(0);
- DEF_VEC(1);
- int op = p_node->param1;
- String optxt;
- switch(op) {
- case VEC_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
- case VEC_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
- case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
- case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
- case VEC_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_CROSS: optxt = "cross("+p_inputs[0]+","+p_inputs[1]+");"; break;
- }
- code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
-
- }break;
- case NODE_VEC_SCALAR_OP: {
- DEF_VEC(0);
- DEF_SCALAR(1);
- int op = p_node->param1;
- String optxt;
- switch(op) {
- case VEC_SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
- case VEC_SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
- case VEC_SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
- }
- code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
-
- }break;
- case NODE_RGB_OP: {
- DEF_COLOR(0);
- DEF_COLOR(1);
-
- int op = p_node->param1;
- static const char*axisn[3]={"x","y","z"};
- switch(op) {
- case RGB_OP_SCREEN: {
-
- code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n";
- } break;
- case RGB_OP_DIFFERENCE: {
-
- code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
- } break;
- case RGB_OP_DARKEN: {
-
- code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n";
- } break;
- case RGB_OP_LIGHTEN: {
-
- code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n";
-
- } break;
- case RGB_OP_OVERLAY: {
-
- code += OUTNAME(p_node->id,0)+";\n";
- for(int i=0;i<3;i++) {
- code += "{\n";
- code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
- code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
- code += "\tif (base < 0.5) {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n";
- code += "\t} else {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
- code += "\t}\n";
- code += "}\n";
- }
-
- } break;
- case RGB_OP_DODGE: {
-
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n";
-
- } break;
- case RGB_OP_BURN: {
-
- code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n";
- } break;
- case RGB_OP_SOFT_LIGHT: {
-
- code += OUTNAME(p_node->id,0)+";\n";
- for(int i=0;i<3;i++) {
- code += "{\n";
- code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
- code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
- code += "\tif (base < 0.5) {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n";
- code += "\t} else {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n";
- code += "\t}\n";
- code += "}\n";
- }
-
- } break;
- case RGB_OP_HARD_LIGHT: {
-
- code += OUTNAME(p_node->id,0)+";\n";
- for(int i=0;i<3;i++) {
- code += "{\n";
- code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
- code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
- code += "\tif (base < 0.5) {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n";
- code += "\t} else {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n";
- code += "\t}\n";
- code += "}\n";
- }
-
- } break;
- }
- }break;
- case NODE_XFORM_MULT: {
- DEF_MATRIX(0);
- DEF_MATRIX(1);
-
- code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
-
- }break;
- case NODE_XFORM_VEC_MULT: {
- DEF_MATRIX(0);
- DEF_VEC(1);
-
- bool no_translation = p_node->param1;
- if (no_translation) {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",0)).xyz;\n";
- } else {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",1)).xyz;\n";
- }
-
- }break;
- case NODE_XFORM_VEC_INV_MULT: {
- DEF_VEC(0);
- DEF_MATRIX(1);
- bool no_translation = p_node->param1;
- if (no_translation) {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
- } else {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",1)).xyz;\n";
- }
- }break;
- case NODE_SCALAR_FUNC: {
- DEF_SCALAR(0);
- static const char*scalar_func_id[SCALAR_MAX_FUNC]={
- "sin($)",
- "cos($)",
- "tan($)",
- "asin($)",
- "acos($)",
- "atan($)",
- "sinh($)",
- "cosh($)",
- "tanh($)",
- "log($)",
- "exp($)",
- "sqrt($)",
- "abs($)",
- "sign($)",
- "floor($)",
- "round($)",
- "ceil($)",
- "fract($)",
- "min(max($,0),1)",
- "-($)",
- };
-
- int func = p_node->param1;
- ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
- code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n";
-
- } break;
- case NODE_VEC_FUNC: {
- DEF_VEC(0);
- static const char*vec_func_id[VEC_MAX_FUNC]={
- "normalize($)",
- "max(min($,vec3(1,1,1)),vec3(0,0,0))",
- "-($)",
- "1.0/($)",
- "",
- "",
- };
-
-
- int func = p_node->param1;
- ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
- if (func==VEC_FUNC_RGB2HSV) {
- code += OUTNAME(p_node->id,0)+";\n";
- code+="{\n";
- code+="\tvec3 c = "+p_inputs[0]+";\n";
- code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
- code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
- code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
- code+="\tfloat d = q.x - min(q.w, q.y);\n";
- code+="\tfloat e = 1.0e-10;\n";
- code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
- code+="}\n";
- } else if (func==VEC_FUNC_HSV2RGB) {
- code += OUTNAME(p_node->id,0)+";\n";
- code+="{\n";
- code+="\tvec3 c = "+p_inputs[0]+";\n";
- code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
- code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
- code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
- code+="}\n";
-
- } else {
- code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n";
- }
- }break;
- case NODE_VEC_LEN: {
- DEF_VEC(0);
-
- code += OUTNAME(p_node->id,0)+"=length("+p_inputs[0]+");\n";
-
- }break;
- case NODE_DOT_PROD: {
- DEF_VEC(0);
- DEF_VEC(1);
- code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
-
- }break;
- case NODE_VEC_TO_SCALAR: {
- DEF_VEC(0);
- code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
- code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
- code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
-
- }break;
- case NODE_SCALAR_TO_VEC: {
- DEF_SCALAR(0);
- DEF_SCALAR(1);
- DEF_SCALAR(2);
- code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
-
- }break;
- case NODE_VEC_TO_XFORM: {
- DEF_VEC(0);
- DEF_VEC(1);
- DEF_VEC(2);
- DEF_VEC(3);
- code += OUTNAME(p_node->id, 0) + "=mat4(" +
- "vec4(" + p_inputs[0] + ".x," + p_inputs[0] + ".y," + p_inputs[0] + ".z, 0.0),"
- "vec4(" + p_inputs[1] + ".x," + p_inputs[1] + ".y," + p_inputs[1] + ".z, 0.0),"
- "vec4(" + p_inputs[2] + ".x," + p_inputs[2] + ".y," + p_inputs[2] + ".z, 0.0),"
- "vec4(" + p_inputs[3] + ".x," + p_inputs[3] + ".y," + p_inputs[3] + ".z, 1.0));\n";
-
- }break;
- case NODE_XFORM_TO_VEC: {
- DEF_MATRIX(0);
- code += OUTNAME(p_node->id, 0) + ";\n";
- code += OUTNAME(p_node->id, 1) + ";\n";
- code += OUTNAME(p_node->id, 2) + ";\n";
- code += OUTNAME(p_node->id, 3) + ";\n";
- code += "{\n";
- code += "\tvec4 xform_row_01=" + p_inputs[0] + ".x;\n";
- code += "\tvec4 xform_row_02=" + p_inputs[0] + ".y;\n";
- code += "\tvec4 xform_row_03=" + p_inputs[0] + ".z;\n";
- code += "\tvec4 xform_row_04=" + p_inputs[0] + ".w;\n";
- code += "\t" + OUTVAR(p_node->id, 0) + "=vec3(xform_row_01.x, xform_row_01.y, xform_row_01.z);\n";
- code += "\t" + OUTVAR(p_node->id, 1) + "=vec3(xform_row_02.x, xform_row_02.y, xform_row_02.z);\n";
- code += "\t" + OUTVAR(p_node->id, 2) + "=vec3(xform_row_03.x, xform_row_03.y, xform_row_03.z);\n";
- code += "\t" + OUTVAR(p_node->id, 3) + "=vec3(xform_row_04.x, xform_row_04.y, xform_row_04.z);\n";
- code += "}\n";
- }break;
- case NODE_SCALAR_INTERP: {
- DEF_SCALAR(0);
- DEF_SCALAR(1);
- DEF_SCALAR(2);
-
- code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
-
- }break;
- case NODE_VEC_INTERP: {
- DEF_VEC(0);
- DEF_VEC(1);
- DEF_SCALAR(2);
- code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
-
- }break;
- case NODE_COLOR_RAMP: {
- DEF_SCALAR(0);
-
- static const int color_ramp_len=512;
- PoolVector<uint8_t> cramp;
- cramp.resize(color_ramp_len*4);
- {
-
- PoolVector<Color> colors=p_node->param1;
- PoolVector<real_t> offsets=p_node->param2;
- int cc =colors.size();
- PoolVector<uint8_t>::Write crw = cramp.write();
- PoolVector<Color>::Read cr = colors.read();
- PoolVector<real_t>::Read ofr = offsets.read();
-
- int at=0;
- Color color_at(0,0,0,1);
- for(int i=0;i<=cc;i++) {
-
- int pos;
- Color to;
- if (i==cc) {
- if (at==color_ramp_len)
- break;
- pos=color_ramp_len;
- to=Color(1,1,1,1);
- } else {
- to=cr[i];
- pos= MIN(ofr[i]*color_ramp_len,color_ramp_len);
- }
- for(int j=at;j<pos;j++) {
- float t = (j-at)/float(pos-at);
- Color c = color_at.linear_interpolate(to,t);
- crw[j*4+0]=Math::fast_ftoi( CLAMP(c.r*255.0,0,255) );
- crw[j*4+1]=Math::fast_ftoi( CLAMP(c.g*255.0,0,255) );
- crw[j*4+2]=Math::fast_ftoi( CLAMP(c.b*255.0,0,255) );
- crw[j*4+3]=Math::fast_ftoi( CLAMP(c.a*255.0,0,255) );
- }
-
- at=pos;
- color_at=to;
- }
- }
-
- Image gradient(color_ramp_len,1,0,Image::FORMAT_RGBA8,cramp);
- Ref<ImageTexture> it = memnew( ImageTexture );
- it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
-
- String crampname= "cramp_"+itos(p_node->id);
- set_default_texture_param(crampname,it);
-
- code +="uniform texture "+crampname+";\n";
- code +="vec4 "+crampname+"_r=tex("+crampname+",vec2("+p_inputs[0]+",0));\n";
- code += OUTNAME(p_node->id,0)+"="+crampname+"_r.rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+crampname+"_r.a;\n";
-
- }break;
- case NODE_CURVE_MAP: {
- DEF_SCALAR(0);
- static const int curve_map_len=256;
- bool mapped[256];
- zeromem(mapped,sizeof(mapped));
- PoolVector<uint8_t> cmap;
- cmap.resize(curve_map_len);
- {
-
- PoolVector<Point2> points=p_node->param1;
- int pc =points.size();
- PoolVector<uint8_t>::Write cmw = cmap.write();
- PoolVector<Point2>::Read pr = points.read();
-
- Vector2 prev=Vector2(0,0);
- Vector2 prev2=Vector2(0,0);
-
- for(int i=-1;i<pc;i++) {
-
- Vector2 next;
- Vector2 next2;
- if (i+1>=pc) {
- next=Vector2(1,1);
- } else {
- next=Vector2(pr[i+1].x,pr[i+1].y);
- }
-
- if (i+2>=pc) {
- next2=Vector2(1,1);
- } else {
- next2=Vector2(pr[i+2].x,pr[i+2].y);
- }
-
- /*if (i==-1 && prev.offset==next.offset) {
- prev=next;
- continue;
- }*/
-
- _plot_curve(prev2,prev,next,next2,cmw.ptr(),mapped);
-
- prev2=prev;
- prev=next;
- }
-
- uint8_t pp=0;
- for(int i=0;i<curve_map_len;i++) {
-
- if (!mapped[i]) {
- cmw[i]=pp;
- } else {
- pp=cmw[i];
- }
- }
- }
-
-
-
- Image gradient(curve_map_len,1,0,Image::FORMAT_L8,cmap);
- Ref<ImageTexture> it = memnew( ImageTexture );
- it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
-
- String cmapname= "cmap_"+itos(p_node->id);
- set_default_texture_param(cmapname,it);
-
- code +="uniform texture "+cmapname+";\n";
- code += OUTNAME(p_node->id,0)+"=tex("+cmapname+",vec2("+p_inputs[0]+",0)).r;\n";
-
- }break;
- case NODE_SCALAR_INPUT: {
- String name = p_node->param1;
- float dv=p_node->param2;
- code +="uniform float "+name+"="+rtos(dv)+";\n";
- code += OUTNAME(p_node->id,0)+"="+name+";\n";
- }break;
- case NODE_VEC_INPUT: {
-
- String name = p_node->param1;
- Vector3 dv=p_node->param2;
- code +="uniform vec3 "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
- code += OUTNAME(p_node->id,0)+"="+name+";\n";
- }break;
- case NODE_RGB_INPUT: {
-
- String name = p_node->param1;
- Color dv= p_node->param2;
-
- code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.b)+","+rtos(dv.a)+");\n";
- code += OUTNAME(p_node->id,0)+"="+name+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+name+".a;\n";
-
- }break;
- case NODE_XFORM_INPUT: {
-
- String name = p_node->param1;
- Transform dv= p_node->param2;
-
- code +="uniform mat4 "+name+"=mat4(\n";
- code+="\tvec4(vec3("+rtos(dv.basis.get_axis(0).x)+","+rtos(dv.basis.get_axis(0).y)+","+rtos(dv.basis.get_axis(0).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(dv.basis.get_axis(1).x)+","+rtos(dv.basis.get_axis(1).y)+","+rtos(dv.basis.get_axis(1).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(dv.basis.get_axis(2).x)+","+rtos(dv.basis.get_axis(2).y)+","+rtos(dv.basis.get_axis(2).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(dv.origin.x)+","+rtos(dv.origin.y)+","+rtos(dv.origin.z)+"),1)\n";
- code+=");";
-
- code += OUTNAME(p_node->id,0)+"="+name+";\n";
-
- }break;
- case NODE_TEXTURE_INPUT: {
- DEF_VEC(0);
- String name = p_node->param1;
- String rname="rt_read_tex"+itos(p_node->id);
- code +="uniform texture "+name+";";
- code +="vec4 "+rname+"=tex("+name+","+p_inputs[0]+".xy);\n";
- code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
-
- }break;
- case NODE_CUBEMAP_INPUT: {
- DEF_VEC(0);
- String name = p_node->param1;
- code +="uniform cubemap "+name+";";
- String rname="rt_read_tex"+itos(p_node->id);
- code +="vec4 "+rname+"=texcube("+name+","+p_inputs[0]+".xy);\n";
- code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
- }break;
- case NODE_DEFAULT_TEXTURE: {
- DEF_VEC(0);
-
- if (get_mode()==MODE_CANVAS_ITEM && p_type==SHADER_TYPE_FRAGMENT) {
-
- String rname="rt_default_tex"+itos(p_node->id);
- code +="vec4 "+rname+"=tex(TEXTURE,"+p_inputs[0]+".xy);\n";
- code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
-
- } else {
- //not supported
- code += OUTNAME(p_node->id,0)+"=vec3(0,0,0);\n";
- code += OUTNAME(p_node->id,1)+"=1.0;\n";
-
- }
- } break;
- case NODE_OUTPUT: {
-
-
- }break;
- case NODE_COMMENT: {
-
- }break;
- case NODE_TYPE_MAX: {
-
- }
- }
-#undef DEF_SCALAR
-#undef DEF_COLOR
-#undef DEF_MATRIX
-#undef DEF_VEC
-}
-
-#endif
diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h
deleted file mode 100644
index e3a68f8572..0000000000
--- a/scene/resources/shader_graph.h
+++ /dev/null
@@ -1,446 +0,0 @@
-/*************************************************************************/
-/* shader_graph.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 SHADER_GRAPH_H
-#define SHADER_GRAPH_H
-
-// FIXME: Needs to be ported to the new 3.0 shader API
-#if 0
-#include "map.h"
-#include "scene/resources/shader.h"
-
-class ShaderGraph : public Shader {
-
- GDCLASS( ShaderGraph, Shader );
- RES_BASE_EXTENSION("vshader");
-
-public:
-
- enum NodeType {
- NODE_INPUT, // all inputs (shader type dependent)
- NODE_SCALAR_CONST, //scalar constant
- NODE_VEC_CONST, //vec3 constant
- NODE_RGB_CONST, //rgb constant (shows a color picker instead)
- NODE_XFORM_CONST, // 4x4 matrix constant
- NODE_TIME, // time in seconds
- NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader)
- NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc)
- NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc)
- NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc)
- NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc.
- NODE_XFORM_MULT, // mat4 x mat4
- NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option)
- NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option)
- NODE_SCALAR_FUNC, // scalar function (sin, cos, etc)
- NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc)
- NODE_VEC_LEN, // vec3 length
- NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output)
- NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs
- NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output
- NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output
- NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
- NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
- NODE_VEC_INTERP, // vec3 interpolation (with optional curve)
- NODE_COLOR_RAMP, //take scalar, output vec3
- NODE_CURVE_MAP, //take scalar, otput scalar
- NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
- NODE_VEC_INPUT, // vec3 uniform (assignable in material)
- NODE_RGB_INPUT, // color uniform (assignable in material)
- NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
- NODE_TEXTURE_INPUT, // texture input (assignable in material)
- NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
- NODE_DEFAULT_TEXTURE,
- NODE_OUTPUT, // output (shader type dependent)
- NODE_COMMENT, // comment
- NODE_TYPE_MAX
- };
-
-
- struct Connection {
-
- int src_id;
- int src_slot;
- int dst_id;
- int dst_slot;
- };
-
- enum SlotType {
-
- SLOT_TYPE_SCALAR,
- SLOT_TYPE_VEC,
- SLOT_TYPE_XFORM,
- SLOT_TYPE_TEXTURE,
- SLOT_MAX
- };
-
- enum ShaderType {
- SHADER_TYPE_VERTEX,
- SHADER_TYPE_FRAGMENT,
- SHADER_TYPE_LIGHT,
- SHADER_TYPE_MAX
- };
-
- enum SlotDir {
- SLOT_IN,
- SLOT_OUT
- };
-
- enum GraphError {
- GRAPH_OK,
- GRAPH_ERROR_CYCLIC,
- GRAPH_ERROR_MISSING_CONNECTIONS
- };
-
-private:
-
- String _find_unique_name(const String& p_base);
-
- enum {SLOT_DEFAULT_VALUE = 0x7FFFFFFF};
- struct SourceSlot {
-
- int id;
- int slot;
- bool operator==(const SourceSlot& p_slot) const {
- return id==p_slot.id && slot==p_slot.slot;
- }
- };
-
- struct Node {
-
- Vector2 pos;
- NodeType type;
- Variant param1;
- Variant param2;
- Map<int, Variant> defaults;
- int id;
- mutable int order; // used for sorting
- int sort_order;
- Map<int,SourceSlot> connections;
-
- };
-
- struct ShaderData {
- Map<int,Node> node_map;
- GraphError error;
- } shader[3];
-
-
-
- struct InOutParamInfo {
- Mode shader_mode;
- ShaderType shader_type;
- const char *name;
- const char *variable;
- const char *postfix;
- SlotType slot_type;
- SlotDir dir;
- };
-
- static const InOutParamInfo inout_param_info[];
-
- struct NodeSlotInfo {
-
- enum { MAX_INS=3, MAX_OUTS=3 };
- NodeType type;
- const SlotType ins[MAX_INS];
- const SlotType outs[MAX_OUTS];
- };
-
- static const NodeSlotInfo node_slot_info[];
-
- bool _pending_update_shader;
- void _update_shader();
- void _request_update();
-
- void _plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds);
- void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code);
-
- Array _get_node_list(ShaderType p_type) const;
- Array _get_connections(ShaderType p_type) const;
-
- void _set_data(const Dictionary& p_data);
- Dictionary _get_data() const;
-protected:
-
- static void _bind_methods();
-
-public:
-
-
- void node_add(ShaderType p_type, NodeType p_node_type, int p_id);
- void node_remove(ShaderType p_which,int p_id);
- void node_set_position(ShaderType p_which,int p_id,const Point2& p_pos);
- Point2 node_get_position(ShaderType p_which,int p_id) const;
-
- void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
- NodeType node_get_type(ShaderType p_which,int p_id) const;
-
- void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value);
- float scalar_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
- Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
- Color rgb_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
- Transform xform_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size);
- int texture_node_get_filter_size(ShaderType p_which,int p_id) const;
-
- void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
- float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
-
- void duplicate_nodes(ShaderType p_which, List<int> &p_nodes);
-
- List<int> generate_ids(ShaderType p_type, int count);
-
- enum ScalarOp {
- SCALAR_OP_ADD,
- SCALAR_OP_SUB,
- SCALAR_OP_MUL,
- SCALAR_OP_DIV,
- SCALAR_OP_MOD,
- SCALAR_OP_POW,
- SCALAR_OP_MAX,
- SCALAR_OP_MIN,
- SCALAR_OP_ATAN2,
- SCALAR_MAX_OP
- };
-
- void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op);
- ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const;
-
- enum VecOp {
- VEC_OP_ADD,
- VEC_OP_SUB,
- VEC_OP_MUL,
- VEC_OP_DIV,
- VEC_OP_MOD,
- VEC_OP_POW,
- VEC_OP_MAX,
- VEC_OP_MIN,
- VEC_OP_CROSS,
- VEC_MAX_OP
- };
-
- void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op);
- VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const;
-
- enum VecScalarOp {
- VEC_SCALAR_OP_MUL,
- VEC_SCALAR_OP_DIV,
- VEC_SCALAR_OP_POW,
- VEC_SCALAR_MAX_OP
- };
-
- void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op);
- VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const;
-
- enum RGBOp {
- RGB_OP_SCREEN,
- RGB_OP_DIFFERENCE,
- RGB_OP_DARKEN,
- RGB_OP_LIGHTEN,
- RGB_OP_OVERLAY,
- RGB_OP_DODGE,
- RGB_OP_BURN,
- RGB_OP_SOFT_LIGHT,
- RGB_OP_HARD_LIGHT,
- RGB_MAX_OP
- };
-
- void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op);
- RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const;
-
- void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation);
- bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const;
-
- enum ScalarFunc {
- SCALAR_FUNC_SIN,
- SCALAR_FUNC_COS,
- SCALAR_FUNC_TAN,
- SCALAR_FUNC_ASIN,
- SCALAR_FUNC_ACOS,
- SCALAR_FUNC_ATAN,
- SCALAR_FUNC_SINH,
- SCALAR_FUNC_COSH,
- SCALAR_FUNC_TANH,
- SCALAR_FUNC_LOG,
- SCALAR_FUNC_EXP,
- SCALAR_FUNC_SQRT,
- SCALAR_FUNC_ABS,
- SCALAR_FUNC_SIGN,
- SCALAR_FUNC_FLOOR,
- SCALAR_FUNC_ROUND,
- SCALAR_FUNC_CEIL,
- SCALAR_FUNC_FRAC,
- SCALAR_FUNC_SATURATE,
- SCALAR_FUNC_NEGATE,
- SCALAR_MAX_FUNC
- };
-
- void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func);
- ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const;
-
- enum VecFunc {
- VEC_FUNC_NORMALIZE,
- VEC_FUNC_SATURATE,
- VEC_FUNC_NEGATE,
- VEC_FUNC_RECIPROCAL,
- VEC_FUNC_RGB2HSV,
- VEC_FUNC_HSV2RGB,
- VEC_MAX_FUNC
- };
-
- void default_set_value(ShaderType p_which,int p_id,int p_param, const Variant& p_value);
- Variant default_get_value(ShaderType p_which,int p_id,int p_param);
-
- void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
- VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
-
- void color_ramp_node_set_ramp(ShaderType p_which,int p_id,const PoolVector<Color>& p_colors, const PoolVector<real_t>& p_offsets);
- PoolVector<Color> color_ramp_node_get_colors(ShaderType p_which,int p_id) const;
- PoolVector<real_t> color_ramp_node_get_offsets(ShaderType p_which,int p_id) const;
-
- void curve_map_node_set_points(ShaderType p_which, int p_id, const PoolVector<Vector2>& p_points);
- PoolVector<Vector2> curve_map_node_get_points(ShaderType p_which,int p_id) const;
-
- void input_node_set_name(ShaderType p_which,int p_id,const String& p_name);
- String input_node_get_name(ShaderType p_which,int p_id);
-
- void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value);
- float scalar_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
- Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
- Color rgb_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
- Transform xform_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref<Texture>& p_texture);
- Ref<Texture> texture_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref<CubeMap>& p_cubemap);
- Ref<CubeMap> cubemap_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment);
- String comment_node_get_text(ShaderType p_which,int p_id) const;
-
- Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
- bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
- void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
-
- void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
-
- bool is_slot_connected(ShaderType p_which,int p_dst_id,int slot_id);
-
- void clear(ShaderType p_which);
-
- Variant node_get_state(ShaderType p_type, int p_node) const;
- void node_set_state(ShaderType p_type, int p_id, const Variant& p_state);
-
- GraphError get_graph_error(ShaderType p_type) const;
-
- int node_count(ShaderType p_which, int p_type);
-
- static int get_type_input_count(NodeType p_type);
- static int get_type_output_count(NodeType p_type);
- static SlotType get_type_input_type(NodeType p_type,int p_idx);
- static SlotType get_type_output_type(NodeType p_type,int p_idx);
- static bool is_type_valid(Mode p_mode,ShaderType p_type);
-
-
- struct SlotInfo {
- String name;
- SlotType type;
- SlotDir dir;
- };
-
- static void get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots);
-
- static int get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
- static int get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
- static SlotType get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
- static SlotType get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
-
-
- ShaderGraph(Mode p_mode);
- ~ShaderGraph();
-};
-
-//helper functions
-
-
-
-
-VARIANT_ENUM_CAST( ShaderGraph::NodeType );
-VARIANT_ENUM_CAST( ShaderGraph::ShaderType );
-VARIANT_ENUM_CAST( ShaderGraph::SlotType );
-VARIANT_ENUM_CAST( ShaderGraph::ScalarOp );
-VARIANT_ENUM_CAST( ShaderGraph::VecOp );
-VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
-VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
-VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
-VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
-VARIANT_ENUM_CAST( ShaderGraph::GraphError );
-
-
-class MaterialShaderGraph : public ShaderGraph {
-
- GDCLASS( MaterialShaderGraph, ShaderGraph );
-
-public:
-
-
- MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) {
-
- }
-};
-
-class CanvasItemShaderGraph : public ShaderGraph {
-
- GDCLASS( CanvasItemShaderGraph, ShaderGraph );
-
-public:
-
-
- CanvasItemShaderGraph() : ShaderGraph(MODE_CANVAS_ITEM) {
-
- }
-};
-
-#endif
-#endif // SHADER_GRAPH_H
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 418d8ce819..a48ce0564b 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -50,6 +50,15 @@ void Shape::add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p
}
}
+real_t Shape::get_margin() const {
+ return margin;
+}
+
+void Shape::set_margin(real_t p_margin) {
+ margin = p_margin;
+ PhysicsServer::get_singleton()->shape_set_margin(shape, margin);
+}
+
Ref<ArrayMesh> Shape::get_debug_mesh() {
if (debug_mesh_cache.is_valid())
@@ -87,12 +96,22 @@ Ref<ArrayMesh> Shape::get_debug_mesh() {
return debug_mesh_cache;
}
-Shape::Shape() {
+void Shape::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &Shape::get_margin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0.04,10,0.01"), "set_margin", "get_margin");
+}
+
+Shape::Shape() :
+ margin(0.04) {
ERR_PRINT("Constructor must not be called!");
}
-Shape::Shape(RID p_shape) {
+Shape::Shape(RID p_shape) :
+ margin(0.04) {
shape = p_shape;
}
diff --git a/scene/resources/shape.h b/scene/resources/shape.h
index ad87a69679..0c44b86e92 100644
--- a/scene/resources/shape.h
+++ b/scene/resources/shape.h
@@ -40,10 +40,13 @@ class Shape : public Resource {
OBJ_SAVE_TYPE(Shape);
RES_BASE_EXTENSION("shape");
RID shape;
+ real_t margin;
Ref<ArrayMesh> debug_mesh_cache;
protected:
+ static void _bind_methods();
+
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape(RID p_shape);
@@ -55,6 +58,9 @@ public:
void add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p_xform);
+ real_t get_margin() const;
+ void set_margin(real_t p_margin);
+
Shape();
~Shape();
};
diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp
index f2d5cb3516..4176aed4d8 100644
--- a/scene/resources/sky_box.cpp
+++ b/scene/resources/sky_box.cpp
@@ -405,7 +405,7 @@ void ProceduralSky::_update_sky() {
} else {
Ref<Image> image = _generate_sky();
- VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
+ VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
VS::get_singleton()->texture_set_data(texture, image);
_radiance_changed();
}
@@ -422,7 +422,7 @@ void ProceduralSky::_queue_update() {
void ProceduralSky::_thread_done(const Ref<Image> &p_image) {
- VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
+ VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT);
VS::get_singleton()->texture_set_data(texture, p_image);
_radiance_changed();
Thread::wait_to_finish(sky_thread);
@@ -532,14 +532,14 @@ ProceduralSky::ProceduralSky() {
texture = VS::get_singleton()->texture_create();
update_queued = false;
- sky_top_color = Color::hex(0x0c74f9ff);
- sky_horizon_color = Color::hex(0x8ed2e8ff);
- sky_curve = 0.25;
+ sky_top_color = Color::hex(0xa5d6f1ff);
+ sky_horizon_color = Color::hex(0xd6eafaff);
+ sky_curve = 0.09;
sky_energy = 1;
- ground_bottom_color = Color::hex(0x1a2530ff);
- ground_horizon_color = Color::hex(0x7bc9f3ff);
- ground_curve = 0.01;
+ ground_bottom_color = Color::hex(0x282f36ff);
+ ground_horizon_color = Color::hex(0x6c655fff);
+ ground_curve = 0.02;
ground_energy = 1;
sun_color = Color(1, 1, 1);
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index ebad00b068..fb81375b0a 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -905,12 +905,20 @@ bool StyleBoxLine::is_vertical() const {
return vertical;
}
-void StyleBoxLine::set_grow(float p_grow) {
- grow = p_grow;
+void StyleBoxLine::set_grow_end(float p_grow_end) {
+ grow_end = p_grow_end;
emit_changed();
}
-float StyleBoxLine::get_grow() const {
- return grow;
+float StyleBoxLine::get_grow_end() const {
+ return grow_end;
+}
+
+void StyleBoxLine::set_grow_begin(float p_grow_begin) {
+ grow_begin = p_grow_begin;
+ emit_changed();
+}
+float StyleBoxLine::get_grow_begin() const {
+ return grow_begin;
}
void StyleBoxLine::_bind_methods() {
@@ -919,13 +927,16 @@ void StyleBoxLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_color"), &StyleBoxLine::get_color);
ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &StyleBoxLine::set_thickness);
ClassDB::bind_method(D_METHOD("get_thickness"), &StyleBoxLine::get_thickness);
- ClassDB::bind_method(D_METHOD("set_grow", "grow"), &StyleBoxLine::set_grow);
- ClassDB::bind_method(D_METHOD("get_grow"), &StyleBoxLine::get_grow);
+ ClassDB::bind_method(D_METHOD("set_grow_begin", "offset"), &StyleBoxLine::set_grow_begin);
+ ClassDB::bind_method(D_METHOD("get_grow_begin"), &StyleBoxLine::get_grow_begin);
+ ClassDB::bind_method(D_METHOD("set_grow_end", "offset"), &StyleBoxLine::set_grow_end);
+ ClassDB::bind_method(D_METHOD("get_grow_end"), &StyleBoxLine::get_grow_end);
ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &StyleBoxLine::set_vertical);
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::REAL, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_begin", "get_grow_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow_end", "get_grow_end");
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");
}
@@ -941,12 +952,12 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Rect2i r = p_rect;
if (vertical) {
- r.position.y -= grow;
- r.size.y += grow * 2;
+ r.position.y -= grow_begin;
+ r.size.y += (grow_begin + grow_end);
r.size.x = thickness;
} else {
- r.position.x -= grow;
- r.size.x += grow * 2;
+ r.position.x -= grow_begin;
+ r.size.x += (grow_begin + grow_end);
r.size.y = thickness;
}
@@ -954,7 +965,8 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
StyleBoxLine::StyleBoxLine() {
- grow = 1.0;
+ grow_begin = 1.0;
+ grow_end = 1.0;
thickness = 1;
color = Color(0.0, 0.0, 0.0);
vertical = false;
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index c1d84fe19f..ed193a1ab4 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -236,7 +236,8 @@ class StyleBoxLine : public StyleBox {
Color color;
int thickness;
bool vertical;
- float grow;
+ float grow_begin;
+ float grow_end;
protected:
virtual float get_style_margin(Margin p_margin) const;
@@ -252,8 +253,11 @@ public:
void set_vertical(bool p_vertical);
bool is_vertical() const;
- void set_grow(float p_grow);
- float get_grow() const;
+ void set_grow_begin(float p_grow);
+ float get_grow_begin() const;
+
+ void set_grow_end(float p_grow);
+ float get_grow_end() const;
virtual Size2 get_center_size() const;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 5a42873d79..81fabf40fe 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -421,6 +421,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_
Array a = commit_to_arrays();
mesh->add_surface_from_arrays(primitive, a, Array(), p_flags);
+
if (material.is_valid())
mesh->surface_set_material(surface, material);
@@ -465,7 +466,7 @@ void SurfaceTool::deindex() {
int idx = 0;
for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- varr[idx++] = E->get();
+ varr.write[idx++] = E->get();
}
vertex_array.clear();
for (List<int>::Element *E = index_array.front(); E; E = E->next()) {
@@ -569,19 +570,19 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array
if (lformat & VS::ARRAY_FORMAT_BONES) {
Vector<int> b;
b.resize(4);
- b[0] = barr[i * 4 + 0];
- b[1] = barr[i * 4 + 1];
- b[2] = barr[i * 4 + 2];
- b[3] = barr[i * 4 + 3];
+ b.write[0] = barr[i * 4 + 0];
+ b.write[1] = barr[i * 4 + 1];
+ b.write[2] = barr[i * 4 + 2];
+ b.write[3] = barr[i * 4 + 3];
v.bones = b;
}
if (lformat & VS::ARRAY_FORMAT_WEIGHTS) {
Vector<float> w;
w.resize(4);
- w[0] = warr[i * 4 + 0];
- w[1] = warr[i * 4 + 1];
- w[2] = warr[i * 4 + 2];
- w[3] = warr[i * 4 + 3];
+ w.write[0] = warr[i * 4 + 0];
+ w.write[1] = warr[i * 4 + 1];
+ w.write[2] = warr[i * 4 + 2];
+ w.write[3] = warr[i * 4 + 3];
v.weights = w;
}
@@ -674,19 +675,19 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li
if (lformat & VS::ARRAY_FORMAT_BONES) {
Vector<int> b;
b.resize(4);
- b[0] = barr[i * 4 + 0];
- b[1] = barr[i * 4 + 1];
- b[2] = barr[i * 4 + 2];
- b[3] = barr[i * 4 + 3];
+ b.write[0] = barr[i * 4 + 0];
+ b.write[1] = barr[i * 4 + 1];
+ b.write[2] = barr[i * 4 + 2];
+ b.write[3] = barr[i * 4 + 3];
v.bones = b;
}
if (lformat & VS::ARRAY_FORMAT_WEIGHTS) {
Vector<float> w;
w.resize(4);
- w[0] = warr[i * 4 + 0];
- w[1] = warr[i * 4 + 1];
- w[2] = warr[i * 4 + 2];
- w[3] = warr[i * 4 + 3];
+ w.write[0] = warr[i * 4 + 0];
+ w.write[1] = warr[i * 4 + 1];
+ w.write[2] = warr[i * 4 + 2];
+ w.write[3] = warr[i * 4 + 3];
v.weights = w;
}
@@ -754,15 +755,11 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
for (List<int>::Element *E = nindices.front(); E; E = E->next()) {
int dst_index = E->get() + vfrom;
- /*
- if (dst_index <0 || dst_index>=vertex_array.size()) {
- print_line("invalid index!");
- }
- */
index_array.push_back(dst_index);
}
- if (index_array.size() % 3)
- print_line("IA not div of 3?");
+ if (index_array.size() % 3) {
+ WARN_PRINT("SurfaceTool: Index array not a multiple of 3.");
+ }
}
//mikktspace callbacks
@@ -845,7 +842,7 @@ void SurfaceTool::generate_tangents() {
vtx.resize(vertex_array.size());
int idx = 0;
for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) {
- vtx[idx++] = E;
+ vtx.write[idx++] = E;
E->get().binormal = Vector3();
E->get().tangent = Vector3();
}
diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp
new file mode 100644
index 0000000000..e2fe0adfc5
--- /dev/null
+++ b/scene/resources/text_file.cpp
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* text_file.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 "text_file.h"
+
+#include "os/file_access.h"
+
+bool TextFile::has_text() const {
+ return text != "";
+}
+
+String TextFile::get_text() const {
+ return text;
+}
+
+void TextFile::set_text(const String &p_code) {
+ text = p_code;
+}
+
+void TextFile::reload_from_file() {
+ load_text(path);
+}
+
+Error TextFile::load_text(const String &p_path) {
+
+ PoolVector<uint8_t> sourcef;
+ Error err;
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (err) {
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ int len = f->get_len();
+ sourcef.resize(len + 1);
+ PoolVector<uint8_t>::Write w = sourcef.write();
+ int r = f->get_buffer(w.ptr(), len);
+ f->close();
+ memdelete(f);
+ ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
+ w[len] = 0;
+
+ String s;
+ if (s.parse_utf8((const char *)w.ptr())) {
+ ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
+ ERR_FAIL_V(ERR_INVALID_DATA);
+ }
+ text = s;
+ path = p_path;
+ return OK;
+}
diff --git a/scene/resources/text_file.h b/scene/resources/text_file.h
new file mode 100644
index 0000000000..40b648eebb
--- /dev/null
+++ b/scene/resources/text_file.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* text_file.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 TEXTFILE_H
+#define TEXTFILE_H
+
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+
+class TextFile : public Resource {
+
+ GDCLASS(TextFile, Resource)
+
+private:
+ String text;
+ String path;
+
+public:
+ virtual bool has_text() const;
+ virtual String get_text() const;
+ virtual void set_text(const String &p_code);
+ virtual void reload_from_file();
+
+ void set_file_path(const String &p_path) { path = p_path; }
+ Error load_text(const String &p_path);
+};
+
+#endif // TEXTFILE_H
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 54f5aea160..811e5c3d2c 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "texture.h"
+#include "bit_mask.h"
#include "core/method_bind_ext.gen.inc"
#include "core/os/os.h"
#include "core_string_names.h"
@@ -39,6 +40,9 @@ Size2 Texture::get_size() const {
return Size2(get_width(), get_height());
}
+bool Texture::is_pixel_opaque(int p_x, int p_y) const {
+ return true;
+}
void Texture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
@@ -124,7 +128,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
Size2 s = p_value;
w = s.width;
h = s.height;
- VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
+ VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0);
} else if (p_name == "_data") {
_set_data(p_value);
} else
@@ -151,13 +155,6 @@ bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
- PropertyHint img_hint = PROPERTY_HINT_NONE;
- if (storage == STORAGE_COMPRESS_LOSSY) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
- } else if (storage == STORAGE_COMPRESS_LOSSLESS) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
- }
-
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, ""));
@@ -183,7 +180,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) {
void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
flags = p_flags;
- VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, p_format, p_flags);
+ VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, 0, p_format, VS::TEXTURE_TYPE_2D, p_flags);
format = p_format;
w = p_width;
h = p_height;
@@ -196,7 +193,7 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags
h = p_image->get_height();
format = p_image->get_format();
- VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), p_flags);
+ VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags);
VisualServer::get_singleton()->texture_set_data(texture, p_image);
_change_notify();
}
@@ -221,9 +218,10 @@ Image::Format ImageTexture::get_format() const {
return format;
}
-
+#ifndef DISABLE_DEPRECATED
Error ImageTexture::load(const String &p_path) {
+ WARN_DEPRECATED
Ref<Image> img;
img.instance();
Error err = img->load(p_path);
@@ -232,12 +230,15 @@ Error ImageTexture::load(const String &p_path) {
}
return err;
}
-
+#endif
void ImageTexture::set_data(const Ref<Image> &p_image) {
+ ERR_FAIL_COND(p_image.is_null());
+
VisualServer::get_singleton()->texture_set_data(texture, p_image);
_change_notify();
+ alpha_cache.unref();
}
void ImageTexture::_resource_path_changed() {
@@ -292,6 +293,41 @@ void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, p_clip_uv);
}
+bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_data();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+ alpha_cache.instance();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / w;
+ int y = p_y * ah / h;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, aw);
+
+ return alpha_cache->get_bit(Point2(x, y));
+ }
+
+ return true;
+}
+
void ImageTexture::set_size_override(const Size2 &p_size) {
Size2 s = p_size;
@@ -299,7 +335,7 @@ void ImageTexture::set_size_override(const Size2 &p_size) {
w = s.x;
if (s.y != 0)
h = s.y;
- VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
+ VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0);
}
void ImageTexture::set_path(const String &p_path, bool p_take_over) {
@@ -350,7 +386,9 @@ void ImageTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "width", "height", "format", "flags"), &ImageTexture::create, DEFVAL(FLAGS_DEFAULT));
ClassDB::bind_method(D_METHOD("create_from_image", "image", "flags"), &ImageTexture::create_from_image, DEFVAL(FLAGS_DEFAULT));
ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("load", "path"), &ImageTexture::load);
+#endif
ClassDB::bind_method(D_METHOD("set_data", "image"), &ImageTexture::set_data);
ClassDB::bind_method(D_METHOD("set_storage", "mode"), &ImageTexture::set_storage);
ClassDB::bind_method(D_METHOD("get_storage"), &ImageTexture::get_storage);
@@ -423,6 +461,8 @@ Image::Format StreamTexture::get_format() const {
Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit) {
+ alpha_cache.unref();
+
ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
@@ -440,7 +480,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
flags = f->get_32(); //texture flags!
uint32_t df = f->get_32(); //data format
-/*
+ /*
print_line("width: " + itos(tw));
print_line("height: " + itos(th));
print_line("flags: " + itos(flags));
@@ -590,7 +630,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
int sh = th;
int mipmaps = Image::get_image_required_mipmaps(tw, th, format);
- int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
+ int total_size = Image::get_image_data_size(tw, th, format, true);
int idx = 0;
int ofs = 0;
@@ -623,7 +663,11 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
memdelete(f);
- if (bytes != total_size - ofs) {
+ int expected = total_size - ofs;
+ if (bytes < expected) {
+ //this is a compatibility workaround for older format, which saved less mipmaps. It is still recommended the image is reimported.
+ zeromem(w.ptr() + bytes, (expected - bytes));
+ } else if (bytes != expected) {
ERR_FAIL_V(ERR_FILE_CORRUPT);
}
}
@@ -646,7 +690,7 @@ Error StreamTexture::load(const String &p_path) {
if (err)
return err;
- VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), image->get_format(), lflags);
+ VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags);
VS::get_singleton()->texture_set_data(texture, image);
w = lw;
@@ -707,6 +751,40 @@ Ref<Image> StreamTexture::get_data() const {
return VS::get_singleton()->texture_get_data(texture);
}
+bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_data();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+ alpha_cache.instance();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / w;
+ int y = p_y * ah / h;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, aw);
+
+ return alpha_cache->get_bit(Point2(x, y));
+ }
+
+ return true;
+}
void StreamTexture::set_flags(uint32_t p_flags) {
flags = p_flags;
VS::get_singleton()->texture_set_flags(texture, flags);
@@ -944,30 +1022,12 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
//this might not necessarily work well if using a rect, needs to be fixed properly
- Rect2 rc = region;
-
if (!atlas.is_valid())
return;
- Rect2 src = p_src_rect;
- src.position += (rc.position - margin.position);
- Rect2 src_c = rc.clip(src);
- if (src_c.size == Size2())
- return;
- Vector2 ofs = (src_c.position - src.position);
-
- Vector2 scale = p_rect.size / p_src_rect.size;
- if (scale.x < 0) {
- float mx = (margin.size.width - margin.position.x);
- mx -= margin.position.x;
- ofs.x = -(ofs.x + mx);
- }
- if (scale.y < 0) {
- float my = margin.size.height - margin.position.y;
- my -= margin.position.y;
- ofs.y = -(ofs.y + my);
- }
- Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale);
+ Rect2 dr;
+ Rect2 src_c;
+ get_rect_region(p_rect, p_src_rect, dr, src_c);
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, filter_clip);
@@ -981,13 +1041,17 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
return false;
Rect2 src = p_src_rect;
+ if (src.size == Size2()) {
+ src.size = rc.size;
+ }
+ Vector2 scale = p_rect.size / src.size;
+
src.position += (rc.position - margin.position);
Rect2 src_c = rc.clip(src);
if (src_c.size == Size2())
return false;
Vector2 ofs = (src_c.position - src.position);
- Vector2 scale = p_rect.size / p_src_rect.size;
if (scale.x < 0) {
float mx = (margin.size.width - margin.position.x);
mx -= margin.position.x;
@@ -1005,6 +1069,15 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
return true;
}
+bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ if (atlas.is_valid()) {
+ return atlas->is_pixel_opaque(p_x + region.position.x + margin.position.x, p_x + region.position.y + margin.position.y);
+ }
+
+ return true;
+}
+
AtlasTexture::AtlasTexture() {
filter_clip = false;
}
@@ -1037,7 +1110,7 @@ bool LargeTexture::has_alpha() const {
void LargeTexture::set_flags(uint32_t p_flags) {
for (int i = 0; i < pieces.size(); i++) {
- pieces[i].texture->set_flags(p_flags);
+ pieces.write[i].texture->set_flags(p_flags);
}
}
@@ -1063,13 +1136,13 @@ int LargeTexture::add_piece(const Point2 &p_offset, const Ref<Texture> &p_textur
void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) {
ERR_FAIL_INDEX(p_idx, pieces.size());
- pieces[p_idx].offset = p_offset;
+ pieces.write[p_idx].offset = p_offset;
};
void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture> &p_texture) {
ERR_FAIL_INDEX(p_idx, pieces.size());
- pieces[p_idx].texture = p_texture;
+ pieces.write[p_idx].texture = p_texture;
};
void LargeTexture::set_size(const Size2 &p_size) {
@@ -1153,7 +1226,6 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
Size2 scale = p_rect.size / size;
- RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
for (int i = 0; i < pieces.size(); i++) {
// TODO
@@ -1168,7 +1240,6 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
Size2 scale = p_rect.size / p_src_rect.size;
- RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
for (int i = 0; i < pieces.size(); i++) {
// TODO
@@ -1184,6 +1255,23 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
}
}
+bool LargeTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ for (int i = 0; i < pieces.size(); i++) {
+
+ // TODO
+ if (!pieces[i].texture.is_valid())
+ continue;
+
+ Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
+ if (rect.has_point(Point2(p_x, p_y))) {
+ return pieces[i].texture->is_pixel_opaque(p_x - rect.position.x, p_y - rect.position.y);
+ }
+ }
+
+ return true;
+}
+
LargeTexture::LargeTexture() {
}
@@ -1193,7 +1281,7 @@ void CubeMap::set_flags(uint32_t p_flags) {
flags = p_flags;
if (_is_valid())
- VS::get_singleton()->texture_set_flags(cubemap, flags | VS::TEXTURE_FLAG_CUBEMAP);
+ VS::get_singleton()->texture_set_flags(cubemap, flags);
}
uint32_t CubeMap::get_flags() const {
@@ -1209,7 +1297,7 @@ void CubeMap::set_side(Side p_side, const Ref<Image> &p_image) {
format = p_image->get_format();
w = p_image->get_width();
h = p_image->get_height();
- VS::get_singleton()->texture_allocate(cubemap, w, h, p_image->get_format(), flags | VS::TEXTURE_FLAG_CUBEMAP);
+ VS::get_singleton()->texture_allocate(cubemap, w, h, 0, p_image->get_format(), VS::TEXTURE_TYPE_CUBEMAP, flags);
}
VS::get_singleton()->texture_set_data(cubemap, p_image, VS::CubeMapSide(p_side));
@@ -1320,13 +1408,6 @@ bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const {
void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const {
- PropertyHint img_hint = PROPERTY_HINT_NONE;
- if (storage == STORAGE_COMPRESS_LOSSY) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY;
- } else if (storage == STORAGE_COMPRESS_LOSSLESS) {
- img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
- }
-
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"));
@@ -1472,7 +1553,7 @@ void CurveTexture::_update() {
Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data));
- VS::get_singleton()->texture_allocate(_texture, _width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_allocate(_texture, _width, 1, 0, Image::FORMAT_RF, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
VS::get_singleton()->texture_set_data(_texture, image);
emit_changed();
@@ -1581,7 +1662,7 @@ void GradientTexture::_update() {
Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
- VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RGBA8, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_allocate(texture, width, 1, 0, Image::FORMAT_RGBA8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
VS::get_singleton()->texture_set_data(texture, image);
emit_changed();
@@ -1669,3 +1750,549 @@ ProxyTexture::~ProxyTexture() {
VS::get_singleton()->free(proxy);
}
+//////////////////////////////////////////////
+
+void AnimatedTexture::_update_proxy() {
+
+ RWLockRead r(rw_lock);
+
+ float delta;
+ if (prev_ticks == 0) {
+ delta = 0;
+ prev_ticks = OS::get_singleton()->get_ticks_usec();
+ } else {
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec();
+ delta = float(double(ticks - prev_ticks) / 1000000.0);
+ prev_ticks = ticks;
+ }
+
+ time += delta;
+
+ float limit;
+
+ if (fps == 0) {
+ limit = 0;
+ } else {
+ limit = 1.0 / fps;
+ }
+
+ int iter_max = frame_count;
+ while (iter_max) {
+ float frame_limit = limit + frames[current_frame].delay_sec;
+
+ if (time > frame_limit) {
+ current_frame++;
+ if (current_frame >= frame_count) {
+ current_frame = 0;
+ }
+ time -= frame_limit;
+ } else {
+ break;
+ }
+ iter_max--;
+ }
+
+ if (frames[current_frame].texture.is_valid()) {
+ VisualServer::get_singleton()->texture_set_proxy(proxy, frames[current_frame].texture->get_rid());
+ }
+}
+
+void AnimatedTexture::set_frames(int p_frames) {
+ ERR_FAIL_COND(p_frames < 1 || p_frames > MAX_FRAMES);
+
+ RWLockWrite r(rw_lock);
+
+ frame_count = p_frames;
+}
+int AnimatedTexture::get_frames() const {
+ return frame_count;
+}
+
+void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture> &p_texture) {
+ ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
+
+ RWLockWrite w(rw_lock);
+
+ frames[p_frame].texture = p_texture;
+}
+Ref<Texture> AnimatedTexture::get_frame_texture(int p_frame) const {
+ ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, Ref<Texture>());
+
+ RWLockRead r(rw_lock);
+
+ return frames[p_frame].texture;
+}
+
+void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) {
+ ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
+
+ RWLockRead r(rw_lock);
+
+ frames[p_frame].delay_sec = p_delay_sec;
+}
+float AnimatedTexture::get_frame_delay(int p_frame) const {
+ ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
+
+ RWLockRead r(rw_lock);
+
+ return frames[p_frame].delay_sec;
+}
+
+void AnimatedTexture::set_fps(float p_fps) {
+ ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000);
+
+ fps = p_fps;
+}
+float AnimatedTexture::get_fps() const {
+ return fps;
+}
+
+int AnimatedTexture::get_width() const {
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return 1;
+ }
+
+ return frames[current_frame].texture->get_width();
+}
+int AnimatedTexture::get_height() const {
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return 1;
+ }
+
+ return frames[current_frame].texture->get_height();
+}
+RID AnimatedTexture::get_rid() const {
+ return proxy;
+}
+
+bool AnimatedTexture::has_alpha() const {
+
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return false;
+ }
+
+ return frames[current_frame].texture->has_alpha();
+}
+
+Ref<Image> AnimatedTexture::get_data() const {
+
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return Ref<Image>();
+ }
+
+ return frames[current_frame].texture->get_data();
+}
+
+bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ RWLockRead r(rw_lock);
+
+ if (frames[current_frame].texture.is_valid()) {
+ return frames[current_frame].texture->is_pixel_opaque(p_x, p_y);
+ }
+ return true;
+}
+
+void AnimatedTexture::set_flags(uint32_t p_flags) {
+}
+uint32_t AnimatedTexture::get_flags() const {
+
+ RWLockRead r(rw_lock);
+
+ if (!frames[current_frame].texture.is_valid()) {
+ return 0;
+ }
+
+ return frames[current_frame].texture->get_flags();
+}
+
+void AnimatedTexture::_validate_property(PropertyInfo &property) const {
+
+ String prop = property.name;
+ if (prop.begins_with("frame_")) {
+ int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
+ if (frame >= frame_count) {
+ property.usage = 0;
+ }
+ }
+}
+
+void AnimatedTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_frames", "frames"), &AnimatedTexture::set_frames);
+ ClassDB::bind_method(D_METHOD("get_frames"), &AnimatedTexture::get_frames);
+
+ ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps);
+ ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps);
+
+ ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
+ ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
+
+ ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay);
+ ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay);
+
+ ClassDB::bind_method(D_METHOD("_update_proxy"), &AnimatedTexture::_update_proxy);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps");
+
+ for (int i = 0; i < MAX_FRAMES; i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_frame_texture", "get_frame_texture", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01"), "set_frame_delay", "get_frame_delay", i);
+ }
+}
+
+AnimatedTexture::AnimatedTexture() {
+ proxy = VS::get_singleton()->texture_create();
+ VisualServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
+ time = 0;
+ frame_count = 1;
+ fps = 4;
+ prev_ticks = 0;
+ current_frame = 0;
+ VisualServer::get_singleton()->connect("frame_pre_draw", this, "_update_proxy");
+
+#ifndef NO_THREADS
+ rw_lock = RWLock::create();
+#else
+ rw_lock = NULL;
+#endif
+}
+
+AnimatedTexture::~AnimatedTexture() {
+ VS::get_singleton()->free(proxy);
+ if (rw_lock) {
+ memdelete(rw_lock);
+ }
+}
+///////////////////////////////
+
+void TextureLayered::set_flags(uint32_t p_flags) {
+ flags = p_flags;
+
+ if (texture.is_valid()) {
+ VS::get_singleton()->texture_set_flags(texture, flags);
+ }
+}
+
+uint32_t TextureLayered::get_flags() const {
+ return flags;
+}
+
+Image::Format TextureLayered::get_format() const {
+ return format;
+}
+
+uint32_t TextureLayered::get_width() const {
+ return width;
+}
+
+uint32_t TextureLayered::get_height() const {
+ return height;
+}
+
+uint32_t TextureLayered::get_depth() const {
+ return depth;
+}
+
+void TextureLayered::_set_data(const Dictionary &p_data) {
+ ERR_FAIL_COND(!p_data.has("width"));
+ ERR_FAIL_COND(!p_data.has("height"));
+ ERR_FAIL_COND(!p_data.has("depth"));
+ ERR_FAIL_COND(!p_data.has("format"));
+ ERR_FAIL_COND(!p_data.has("flags"));
+ ERR_FAIL_COND(!p_data.has("layers"));
+ int w = p_data["width"];
+ int h = p_data["height"];
+ int d = p_data["depth"];
+ Image::Format format = Image::Format(int(p_data["format"]));
+ int flags = p_data["flags"];
+ Array layers = p_data["layers"];
+ ERR_FAIL_COND(layers.size() != d);
+
+ create(w, h, d, format, flags);
+
+ for (int i = 0; i < layers.size(); i++) {
+ Ref<Image> img = layers[i];
+ ERR_CONTINUE(!img.is_valid());
+ ERR_CONTINUE(img->get_format() != format);
+ ERR_CONTINUE(img->get_width() != w);
+ ERR_CONTINUE(img->get_height() != h);
+ set_layer_data(img, i);
+ }
+}
+
+Dictionary TextureLayered::_get_data() const {
+ Dictionary d;
+ d["width"] = width;
+ d["height"] = height;
+ d["depth"] = depth;
+ d["flags"] = flags;
+ d["format"] = format;
+
+ Array layers;
+ for (int i = 0; i < depth; i++) {
+ layers.push_back(get_layer_data(i));
+ }
+ d["layers"] = layers;
+ return d;
+}
+
+void TextureLayered::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags) {
+ VS::get_singleton()->texture_allocate(texture, p_width, p_height, p_depth, p_format, is_3d ? VS::TEXTURE_TYPE_3D : VS::TEXTURE_TYPE_2D_ARRAY, p_flags);
+
+ width = p_width;
+ height = p_height;
+ depth = p_depth;
+
+ flags = p_flags;
+}
+
+void TextureLayered::set_layer_data(const Ref<Image> &p_image, int p_layer) {
+ ERR_FAIL_COND(!texture.is_valid());
+ VS::get_singleton()->texture_set_data(texture, p_image, p_layer);
+}
+
+Ref<Image> TextureLayered::get_layer_data(int p_layer) const {
+
+ ERR_FAIL_COND_V(!texture.is_valid(), Ref<Image>());
+ return VS::get_singleton()->texture_get_data(texture, p_layer);
+}
+
+void TextureLayered::set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap) {
+ ERR_FAIL_COND(!texture.is_valid());
+ VS::get_singleton()->texture_set_data_partial(texture, p_image, 0, 0, p_image->get_width(), p_image->get_height(), p_x_ofs, p_y_ofs, p_mipmap, p_z);
+}
+
+RID TextureLayered::get_rid() const {
+ return texture;
+}
+
+void TextureLayered::set_path(const String &p_path, bool p_take_over) {
+ if (texture.is_valid()) {
+ VS::get_singleton()->texture_set_path(texture, p_path);
+ }
+
+ Resource::set_path(p_path, p_take_over);
+}
+
+void TextureLayered::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextureLayered::set_flags);
+ ClassDB::bind_method(D_METHOD("get_flags"), &TextureLayered::get_flags);
+
+ ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format);
+
+ ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width);
+ ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height);
+ ClassDB::bind_method(D_METHOD("get_depth"), &TextureLayered::get_depth);
+
+ ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &TextureLayered::create, DEFVAL(FLAGS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("set_layer_data", "image", "layer"), &TextureLayered::set_layer_data);
+ ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::get_layer_data);
+ ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &TextureLayered::set_data_partial, DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &TextureLayered::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &TextureLayered::_get_data);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+
+ BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
+ BIND_ENUM_CONSTANT(FLAG_REPEAT);
+ BIND_ENUM_CONSTANT(FLAG_FILTER);
+ BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
+}
+
+TextureLayered::TextureLayered(bool p_3d) {
+ is_3d = p_3d;
+ format = Image::FORMAT_MAX;
+ flags = FLAGS_DEFAULT;
+
+ width = 0;
+ height = 0;
+ depth = 0;
+
+ texture = VS::get_singleton()->texture_create();
+}
+
+TextureLayered::~TextureLayered() {
+ if (texture.is_valid()) {
+ VS::get_singleton()->free(texture);
+ }
+}
+
+RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error) {
+
+ if (r_error) {
+ *r_error = ERR_CANT_OPEN;
+ }
+
+ Ref<TextureLayered> lt;
+ Ref<Texture3D> tex3d;
+ Ref<TextureArray> texarr;
+
+ if (p_path.ends_with("tex3d")) {
+ tex3d.instance();
+ lt = tex3d;
+ } else if (p_path.ends_with("texarr")) {
+ texarr.instance();
+ lt = texarr;
+ } else {
+ ERR_EXPLAIN("Unrecognized layered texture extension");
+ ERR_FAIL_V(RES());
+ }
+
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V(!f, RES());
+
+ uint8_t header[5] = { 0, 0, 0, 0, 0 };
+ f->get_buffer(header, 4);
+
+ if (header[0] == 'G' && header[1] == 'D' && header[2] == '3' && header[3] == 'T') {
+ if (tex3d.is_null()) {
+ memdelete(f);
+ ERR_FAIL_COND_V(tex3d.is_null(), RES())
+ }
+ } else if (header[0] == 'G' && header[1] == 'D' && header[2] == 'A' && header[3] == 'T') {
+ if (texarr.is_null()) {
+ memdelete(f);
+ ERR_FAIL_COND_V(texarr.is_null(), RES())
+ }
+ } else {
+
+ ERR_EXPLAIN("Unrecognized layered texture file format: " + String((const char *)header));
+ ERR_FAIL_V(RES());
+ }
+
+ int tw = f->get_32();
+ int th = f->get_32();
+ int td = f->get_32();
+ int flags = f->get_32(); //texture flags!
+ Image::Format format = Image::Format(f->get_32());
+ uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed
+
+ lt->create(tw, th, td, format, flags);
+
+ for (int layer = 0; layer < td; layer++) {
+
+ Ref<Image> image;
+ image.instance();
+
+ if (compression == COMPRESSION_LOSSLESS) {
+ //look for a PNG file inside
+
+ int mipmaps = f->get_32();
+ Vector<Ref<Image> > mipmap_images;
+
+ for (int i = 0; i < mipmaps; i++) {
+ uint32_t size = f->get_32();
+
+ PoolVector<uint8_t> pv;
+ pv.resize(size);
+ {
+ PoolVector<uint8_t>::Write w = pv.write();
+ f->get_buffer(w.ptr(), size);
+ }
+
+ Ref<Image> img = Image::lossless_unpacker(pv);
+
+ if (img.is_null() || img->empty() || format != img->get_format()) {
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ }
+ memdelete(f);
+ ERR_FAIL_V(RES());
+ }
+
+ mipmap_images.push_back(img);
+ }
+
+ if (mipmap_images.size() == 1) {
+
+ image = mipmap_images[0];
+
+ } else {
+ int total_size = Image::get_image_data_size(tw, th, format, true);
+ PoolVector<uint8_t> img_data;
+ img_data.resize(total_size);
+
+ {
+ PoolVector<uint8_t>::Write w = img_data.write();
+
+ int ofs = 0;
+ for (int i = 0; i < mipmap_images.size(); i++) {
+
+ PoolVector<uint8_t> id = mipmap_images[i]->get_data();
+ int len = id.size();
+ PoolVector<uint8_t>::Read r = id.read();
+ copymem(&w[ofs], r.ptr(), len);
+ ofs += len;
+ }
+ }
+
+ image->create(tw, th, true, format, img_data);
+ if (image->empty()) {
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ }
+ memdelete(f);
+ ERR_FAIL_V(RES());
+ }
+ }
+
+ } else {
+
+ //look for regular format
+ bool mipmaps = (flags & Texture::FLAG_MIPMAPS);
+ int total_size = Image::get_image_data_size(tw, th, format, mipmaps);
+
+ PoolVector<uint8_t> img_data;
+ img_data.resize(total_size);
+
+ {
+ PoolVector<uint8_t>::Write w = img_data.write();
+ int bytes = f->get_buffer(w.ptr(), total_size);
+ if (bytes != total_size) {
+ if (r_error) {
+ *r_error = ERR_FILE_CORRUPT;
+ memdelete(f);
+ }
+ ERR_FAIL_V(RES());
+ }
+ }
+
+ image->create(tw, th, mipmaps, format, img_data);
+ }
+
+ lt->set_layer_data(image, layer);
+ }
+
+ if (r_error)
+ *r_error = OK;
+
+ return lt;
+}
+
+void ResourceFormatLoaderTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("tex3d");
+ p_extensions->push_back("texarr");
+}
+bool ResourceFormatLoaderTextureLayered::handles_type(const String &p_type) const {
+ return p_type == "Texture3D" || p_type == "TextureArray";
+}
+String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_path) const {
+
+ if (p_path.get_extension().to_lower() == "tex3d")
+ return "Texture3D";
+ if (p_path.get_extension().to_lower() == "texarr")
+ return "TextureArray";
+ return "";
+}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index d81fd3b19b..79e6d2cdf9 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -33,11 +33,13 @@
#include "curve.h"
#include "io/resource_loader.h"
-#include "math_2d.h"
+#include "os/mutex.h"
+#include "os/rw_lock.h"
+#include "os/thread_safe.h"
+#include "rect2.h"
#include "resource.h"
#include "scene/resources/color_ramp.h"
#include "servers/visual_server.h"
-
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -66,6 +68,8 @@ public:
virtual Size2 get_size() const;
virtual RID get_rid() const = 0;
+ virtual bool is_pixel_opaque(int p_x, int p_y) const;
+
virtual bool has_alpha() const = 0;
virtual void set_flags(uint32_t p_flags) = 0;
@@ -83,6 +87,8 @@ public:
VARIANT_ENUM_CAST(Texture::Flags);
+class BitMap;
+
class ImageTexture : public Texture {
GDCLASS(ImageTexture, Texture);
@@ -103,6 +109,7 @@ private:
Storage storage;
Size2 size_override;
float lossy_storage_quality;
+ mutable Ref<BitMap> alpha_cache;
protected:
virtual void reload_from_file();
@@ -124,7 +131,9 @@ public:
void set_flags(uint32_t p_flags);
uint32_t get_flags() const;
Image::Format get_format() const;
+#ifndef DISABLE_DEPRECATED
Error load(const String &p_path);
+#endif
void set_data(const Ref<Image> &p_image);
Ref<Image> get_data() const;
@@ -140,6 +149,8 @@ public:
void set_storage(Storage p_storage);
Storage get_storage() const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
void set_lossy_storage_quality(float p_lossy_storage_quality);
float get_lossy_storage_quality() const;
@@ -180,6 +191,7 @@ private:
Image::Format format;
uint32_t flags;
int w, h;
+ mutable Ref<BitMap> alpha_cache;
virtual void reload_from_file();
@@ -212,6 +224,7 @@ public:
virtual bool has_alpha() const;
virtual void set_flags(uint32_t p_flags);
+ bool is_pixel_opaque(int p_x, int p_y) const;
virtual Ref<Image> get_data() const;
@@ -269,6 +282,8 @@ public:
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
AtlasTexture();
};
@@ -316,6 +331,8 @@ public:
virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
LargeTexture();
};
@@ -400,6 +417,88 @@ VARIANT_ENUM_CAST(CubeMap::Flags)
VARIANT_ENUM_CAST(CubeMap::Side)
VARIANT_ENUM_CAST(CubeMap::Storage)
+class TextureLayered : public Resource {
+
+ GDCLASS(TextureLayered, Resource)
+
+public:
+ enum Flags {
+ FLAG_MIPMAPS = VisualServer::TEXTURE_FLAG_MIPMAPS,
+ FLAG_REPEAT = VisualServer::TEXTURE_FLAG_REPEAT,
+ FLAG_FILTER = VisualServer::TEXTURE_FLAG_FILTER,
+ FLAG_CONVERT_TO_LINEAR = VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR,
+ FLAGS_DEFAULT = FLAG_FILTER,
+ };
+
+private:
+ bool is_3d;
+ RID texture;
+ Image::Format format;
+ uint32_t flags;
+
+ int width;
+ int height;
+ int depth;
+
+ void _set_data(const Dictionary &p_data);
+ Dictionary _get_data() const;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_flags(uint32_t p_flags);
+ uint32_t get_flags() const;
+
+ Image::Format get_format() const;
+ uint32_t get_width() const;
+ uint32_t get_height() const;
+ uint32_t get_depth() const;
+
+ void create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags = FLAGS_DEFAULT);
+ void set_layer_data(const Ref<Image> &p_image, int p_layer);
+ Ref<Image> get_layer_data(int p_layer) const;
+ void set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap = 0);
+
+ virtual RID get_rid() const;
+ virtual void set_path(const String &p_path, bool p_take_over = false);
+
+ TextureLayered(bool p_3d = false);
+ ~TextureLayered();
+};
+
+VARIANT_ENUM_CAST(TextureLayered::Flags)
+
+class Texture3D : public TextureLayered {
+
+ GDCLASS(Texture3D, TextureLayered)
+public:
+ Texture3D() :
+ TextureLayered(true) {}
+};
+
+class TextureArray : public TextureLayered {
+
+ GDCLASS(TextureArray, TextureLayered)
+public:
+ TextureArray() :
+ TextureLayered(false) {}
+};
+
+class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader {
+public:
+ enum Compression {
+ COMPRESSION_LOSSLESS,
+ COMPRESSION_VRAM,
+ COMPRESSION_UNCOMPRESSED
+ };
+
+ 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 CurveTexture : public Texture {
GDCLASS(CurveTexture, Texture)
@@ -521,4 +620,73 @@ public:
~ProxyTexture();
};
+class AnimatedTexture : public Texture {
+ GDCLASS(AnimatedTexture, Texture)
+
+ //use readers writers lock for this, since its far more times read than written to
+ RWLock *rw_lock;
+
+private:
+ enum {
+ MAX_FRAMES = 256
+ };
+
+ RID proxy;
+
+ struct Frame {
+
+ Ref<Texture> texture;
+ float delay_sec;
+
+ Frame() {
+ delay_sec = 0;
+ }
+ };
+
+ Frame frames[MAX_FRAMES];
+ int frame_count;
+ int current_frame;
+
+ float fps;
+
+ float time;
+
+ uint64_t prev_ticks;
+
+ void _update_proxy();
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_frames(int p_frames);
+ int get_frames() const;
+
+ void set_frame_texture(int p_frame, const Ref<Texture> &p_texture);
+ Ref<Texture> get_frame_texture(int p_frame) const;
+
+ void set_frame_delay(int p_frame, float p_delay_sec);
+ float get_frame_delay(int p_frame) const;
+
+ void set_fps(float p_fps);
+ float get_fps() const;
+
+ virtual int get_width() const;
+ virtual int get_height() const;
+ virtual RID get_rid() const;
+
+ virtual bool has_alpha() const;
+
+ virtual void set_flags(uint32_t p_flags);
+ virtual uint32_t get_flags() const;
+
+ virtual Ref<Image> get_data() const;
+
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
+ AnimatedTexture();
+ ~AnimatedTexture();
+};
+
#endif
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index c23f237c75..e0d4038e7e 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -55,12 +55,12 @@ class Theme : public Resource {
void _unref_font(Ref<Font> p_sc);
void _emit_theme_changed();
- HashMap<StringName, HashMap<StringName, Ref<Texture>, StringNameHasher>, StringNameHasher> icon_map;
- HashMap<StringName, HashMap<StringName, Ref<StyleBox>, StringNameHasher>, StringNameHasher> style_map;
- HashMap<StringName, HashMap<StringName, Ref<Font>, StringNameHasher>, StringNameHasher> font_map;
- HashMap<StringName, HashMap<StringName, Ref<Shader>, StringNameHasher>, StringNameHasher> shader_map;
- HashMap<StringName, HashMap<StringName, Color, StringNameHasher>, StringNameHasher> color_map;
- HashMap<StringName, HashMap<StringName, int, StringNameHasher>, StringNameHasher> constant_map;
+ HashMap<StringName, HashMap<StringName, Ref<Texture> > > icon_map;
+ HashMap<StringName, HashMap<StringName, Ref<StyleBox> > > style_map;
+ HashMap<StringName, HashMap<StringName, Ref<Font> > > font_map;
+ HashMap<StringName, HashMap<StringName, Ref<Shader> > > shader_map;
+ HashMap<StringName, HashMap<StringName, Color> > color_map;
+ HashMap<StringName, HashMap<StringName, int> > constant_map;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 58057cda0c..23074b4bae 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -59,7 +59,13 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
tile_set_region(id, p_value);
else if (what == "tile_mode")
tile_set_tile_mode(id, (TileMode)((int)p_value));
- else if (what.left(9) == "autotile/") {
+ else if (what == "is_autotile") {
+ // backward compatibility for Godot 3.0.x
+ // autotile used to be a bool, it's now an enum
+ bool is_autotile = p_value;
+ if (is_autotile)
+ tile_set_tile_mode(id, AUTO_TILE);
+ } else if (what.left(9) == "autotile/") {
what = what.right(9);
if (what == "bitmask_mode")
autotile_set_bitmask_mode(id, (BitmaskMode)((int)p_value));
@@ -262,7 +268,7 @@ 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::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE"));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_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));
@@ -272,6 +278,12 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
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));
+ } else if (tile_get_tile_mode(id) == ATLAS_TILE) {
+ 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::VECTOR2, pre + "occluder_offset"));
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"));
@@ -494,8 +506,21 @@ uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
const Map<Vector2, uint16_t> &TileSet::autotile_get_bitmask_map(int p_id) {
static Map<Vector2, uint16_t> dummy;
+ static Map<Vector2, uint16_t> dummy_atlas;
ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
- return tile_map[p_id].autotile_data.flags;
+ if (tile_get_tile_mode(p_id) == ATLAS_TILE) {
+ dummy_atlas = Map<Vector2, uint16_t>();
+ Rect2 region = tile_get_region(p_id);
+ Size2 size = autotile_get_size(p_id);
+ float spacing = autotile_get_spacing(p_id);
+ for (int x = 0; x < (region.size.x / (size.x + spacing)); x++) {
+ for (int y = 0; y < (region.size.y / (size.y + spacing)); y++) {
+ dummy_atlas.insert(Vector2(x, y), 0);
+ }
+ }
+ return dummy_atlas;
+ } else
+ return tile_map[p_id].autotile_data.flags;
}
Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node, const Vector2 &p_tile_location) {
@@ -576,7 +601,7 @@ void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_sha
ERR_FAIL_COND(!tile_map.has(p_id));
if (tile_map[p_id].shapes_data.size() <= p_shape_id)
tile_map[p_id].shapes_data.resize(p_shape_id + 1);
- tile_map[p_id].shapes_data[p_shape_id].shape = p_shape;
+ tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape;
emit_changed();
}
@@ -594,7 +619,7 @@ void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform
ERR_FAIL_COND(!tile_map.has(p_id));
if (tile_map[p_id].shapes_data.size() <= p_shape_id)
tile_map[p_id].shapes_data.resize(p_shape_id + 1);
- tile_map[p_id].shapes_data[p_shape_id].shape_transform = p_offset;
+ tile_map[p_id].shapes_data.write[p_shape_id].shape_transform = p_offset;
emit_changed();
}
@@ -622,7 +647,7 @@ void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_
ERR_FAIL_COND(!tile_map.has(p_id));
if (tile_map[p_id].shapes_data.size() <= p_shape_id)
tile_map[p_id].shapes_data.resize(p_shape_id + 1);
- tile_map[p_id].shapes_data[p_shape_id].one_way_collision = p_one_way;
+ tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision = p_one_way;
emit_changed();
}
@@ -915,6 +940,8 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile);
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("autotile_set_size", "id", "size"), &TileSet::autotile_set_size);
+ ClassDB::bind_method(D_METHOD("autotile_get_size", "id"), &TileSet::autotile_get_size);
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);
@@ -923,12 +950,16 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("tile_get_normal_map", "id"), &TileSet::tile_get_normal_map);
ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material);
ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material);
+ ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate);
+ ClassDB::bind_method(D_METHOD("tile_get_modulate", "id"), &TileSet::tile_get_modulate);
ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset);
ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset);
ClassDB::bind_method(D_METHOD("tile_set_region", "id", "region"), &TileSet::tile_set_region);
ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region);
ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape"), &TileSet::tile_set_shape);
ClassDB::bind_method(D_METHOD("tile_get_shape", "id", "shape_id"), &TileSet::tile_get_shape);
+ ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset);
+ ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset);
ClassDB::bind_method(D_METHOD("tile_set_shape_transform", "id", "shape_id", "shape_transform"), &TileSet::tile_set_shape_transform);
ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform);
ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way);
@@ -974,7 +1005,7 @@ void TileSet::_bind_methods() {
BIND_ENUM_CONSTANT(SINGLE_TILE);
BIND_ENUM_CONSTANT(AUTO_TILE);
- BIND_ENUM_CONSTANT(ANIMATED_TILE);
+ BIND_ENUM_CONSTANT(ATLAS_TILE);
}
TileSet::TileSet() {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index ec635ee5cc..40eee2700d 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -75,7 +75,7 @@ public:
enum TileMode {
SINGLE_TILE,
AUTO_TILE,
- ANIMATED_TILE
+ ATLAS_TILE
};
struct AutotileData {
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
new file mode 100644
index 0000000000..46b936b731
--- /dev/null
+++ b/scene/resources/visual_shader.cpp
@@ -0,0 +1,1583 @@
+/*************************************************************************/
+/* visual_shader.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 "visual_shader.h"
+#include "servers/visual/shader_types.h"
+#include "vmap.h"
+
+void VisualShaderNode::set_output_port_for_preview(int p_index) {
+
+ port_preview = p_index;
+}
+
+int VisualShaderNode::get_output_port_for_preview() const {
+
+ return port_preview;
+}
+
+void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p_value) {
+ default_input_values[p_port] = p_value;
+ emit_changed();
+}
+
+Variant VisualShaderNode::get_input_port_default_value(int p_port) const {
+ if (default_input_values.has(p_port)) {
+ return default_input_values[p_port];
+ }
+
+ return Variant();
+}
+
+bool VisualShaderNode::is_port_separator(int p_index) const {
+ return false;
+}
+
+Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
+ return Vector<VisualShader::DefaultTextureParam>();
+}
+String VisualShaderNode::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return String();
+}
+
+Vector<StringName> VisualShaderNode::get_editable_properties() const {
+ return Vector<StringName>();
+}
+
+Array VisualShaderNode::_get_default_input_values() const {
+
+ Array ret;
+ for (Map<int, Variant>::Element *E = default_input_values.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ ret.push_back(E->get());
+ }
+ return ret;
+}
+void VisualShaderNode::_set_default_input_values(const Array &p_values) {
+
+ if (p_values.size() % 2 == 0) {
+ for (int i = 0; i < p_values.size(); i += 2) {
+ default_input_values[p_values[i + 0]] = p_values[i + 1];
+ }
+ }
+
+ emit_changed();
+}
+
+String VisualShaderNode::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+ return String();
+}
+
+void VisualShaderNode::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview);
+ ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview);
+
+ ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value);
+ ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value);
+
+ ClassDB::bind_method(D_METHOD("_set_default_input_values", "values"), &VisualShaderNode::_set_default_input_values);
+ ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualShaderNode::_get_default_input_values);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values");
+ ADD_SIGNAL(MethodInfo("editor_refresh_request"));
+}
+
+VisualShaderNode::VisualShaderNode() {
+ port_preview = -1;
+}
+
+/////////////////////////////////////////////////////////
+
+void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
+ ERR_FAIL_COND(p_node.is_null());
+ ERR_FAIL_COND(p_id < 2);
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ Graph *g = &graph[p_type];
+ ERR_FAIL_COND(g->nodes.has(p_id));
+ Node n;
+ n.node = p_node;
+ n.position = p_position;
+
+ Ref<VisualShaderNodeUniform> uniform = n.node;
+ if (uniform.is_valid()) {
+ String valid_name = validate_uniform_name(uniform->get_uniform_name(), uniform);
+ uniform->set_uniform_name(valid_name);
+ }
+
+ Ref<VisualShaderNodeInput> input = n.node;
+ if (input.is_valid()) {
+ input->shader_mode = shader_mode;
+ input->shader_type = p_type;
+ input->connect("input_type_changed", this, "_input_type_changed", varray(p_type, p_id));
+ }
+
+ n.node->connect("changed", this, "_queue_update");
+
+ g->nodes[p_id] = n;
+
+ _queue_update();
+}
+
+void VisualShader::set_node_position(Type p_type, int p_id, const Vector2 &p_position) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ Graph *g = &graph[p_type];
+ ERR_FAIL_COND(!g->nodes.has(p_id));
+ g->nodes[p_id].position = p_position;
+}
+
+Vector2 VisualShader::get_node_position(Type p_type, int p_id) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Vector2());
+ const Graph *g = &graph[p_type];
+ ERR_FAIL_COND_V(!g->nodes.has(p_id), Vector2());
+ return g->nodes[p_id].position;
+}
+Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>());
+ const Graph *g = &graph[p_type];
+ ERR_FAIL_COND_V(!g->nodes.has(p_id), Ref<VisualShaderNode>());
+ return g->nodes[p_id].node;
+}
+
+Vector<int> VisualShader::get_node_list(Type p_type) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Vector<int>());
+ const Graph *g = &graph[p_type];
+
+ Vector<int> ret;
+ for (Map<int, Node>::Element *E = g->nodes.front(); E; E = E->next()) {
+ ret.push_back(E->key());
+ }
+
+ return ret;
+}
+int VisualShader::get_valid_node_id(Type p_type) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, NODE_ID_INVALID);
+ const Graph *g = &graph[p_type];
+ return g->nodes.size() ? MAX(2, g->nodes.back()->key() + 1) : 2;
+}
+
+int VisualShader::find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const {
+ for (const Map<int, Node>::Element *E = graph[p_type].nodes.front(); E; E = E->next()) {
+ if (E->get().node == p_node)
+ return E->key();
+ }
+
+ return NODE_ID_INVALID;
+}
+
+void VisualShader::remove_node(Type p_type, int p_id) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ ERR_FAIL_COND(p_id < 2);
+ Graph *g = &graph[p_type];
+ ERR_FAIL_COND(!g->nodes.has(p_id));
+
+ Ref<VisualShaderNodeInput> input = g->nodes[p_id].node;
+ if (input.is_valid()) {
+ input->disconnect("input_type_changed", this, "_input_type_changed");
+ }
+
+ g->nodes[p_id].node->disconnect("changed", this, "_queue_update");
+
+ g->nodes.erase(p_id);
+
+ for (List<Connection>::Element *E = g->connections.front(); E;) {
+ List<Connection>::Element *N = E->next();
+ if (E->get().from_node == p_id || E->get().to_node == p_id) {
+ g->connections.erase(E);
+ }
+ E = N;
+ }
+
+ _queue_update();
+}
+
+bool VisualShader::is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false);
+ const Graph *g = &graph[p_type];
+
+ for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+
+ if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
+
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false);
+ const Graph *g = &graph[p_type];
+
+ if (!g->nodes.has(p_from_node))
+ return false;
+
+ if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_output_port_count())
+ return false;
+
+ if (!g->nodes.has(p_to_node))
+ return false;
+
+ if (p_to_port < 0 || p_to_port >= g->nodes[p_to_node].node->get_input_port_count())
+ return false;
+
+ VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
+ VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
+
+ if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) {
+ return false;
+ }
+
+ for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+
+ if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, ERR_CANT_CONNECT);
+ Graph *g = &graph[p_type];
+
+ ERR_FAIL_COND_V(!g->nodes.has(p_from_node), ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_output_port_count(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER);
+
+ VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port);
+ VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port);
+
+ if (MAX(0, from_port_type - 1) != (MAX(0, to_port_type - 1))) {
+ ERR_EXPLAIN("Incompatible port types (scalar/vec with transform");
+ ERR_FAIL_V(ERR_INVALID_PARAMETER)
+ return ERR_INVALID_PARAMETER;
+ }
+
+ for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+
+ if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
+ ERR_FAIL_V(ERR_ALREADY_EXISTS);
+ }
+ }
+
+ Connection c;
+ c.from_node = p_from_node;
+ c.from_port = p_from_port;
+ c.to_node = p_to_node;
+ c.to_port = p_to_port;
+ g->connections.push_back(c);
+
+ _queue_update();
+ return OK;
+}
+void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ Graph *g = &graph[p_type];
+
+ for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+
+ if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
+ g->connections.erase(E);
+ _queue_update();
+ return;
+ }
+ }
+}
+
+Array VisualShader::_get_node_connections(Type p_type) const {
+ ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Array());
+ const Graph *g = &graph[p_type];
+
+ Array ret;
+ for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+ Dictionary d;
+ d["from_node"] = E->get().from_node;
+ d["from_port"] = E->get().from_port;
+ d["to_node"] = E->get().to_node;
+ d["to_port"] = E->get().to_port;
+ ret.push_back(d);
+ }
+
+ return ret;
+}
+void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connections) const {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ const Graph *g = &graph[p_type];
+
+ for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
+ r_connections->push_back(E->get());
+ }
+}
+
+void VisualShader::set_mode(Mode p_mode) {
+ if (shader_mode == p_mode) {
+ return;
+ }
+
+ //erase input/output connections
+ modes.clear();
+ flags.clear();
+ shader_mode = p_mode;
+ for (int i = 0; i < TYPE_MAX; i++) {
+
+ for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
+
+ Ref<VisualShaderNodeInput> input = E->get().node;
+ if (input.is_valid()) {
+ input->shader_mode = shader_mode;
+ //input->input_index = 0;
+ }
+ }
+
+ Ref<VisualShaderNodeOutput> output = graph[i].nodes[NODE_ID_OUTPUT].node;
+ output->shader_mode = shader_mode;
+
+ // clear connections since they are no longer valid
+ for (List<Connection>::Element *E = graph[i].connections.front(); E;) {
+
+ bool keep = true;
+
+ List<Connection>::Element *N = E->next();
+
+ int from = E->get().from_node;
+ int to = E->get().to_node;
+
+ if (!graph[i].nodes.has(from)) {
+ keep = false;
+ } else {
+ Ref<VisualShaderNode> from_node = graph[i].nodes[from].node;
+ if (from_node->is_class("VisualShaderNodeOutput") || from_node->is_class("VisualShaderNodeInput")) {
+ keep = false;
+ }
+ }
+
+ if (!graph[i].nodes.has(to)) {
+ keep = false;
+ } else {
+ Ref<VisualShaderNode> to_node = graph[i].nodes[to].node;
+ if (to_node->is_class("VisualShaderNodeOutput") || to_node->is_class("VisualShaderNodeInput")) {
+ keep = false;
+ }
+ }
+
+ if (!keep) {
+ graph[i].connections.erase(E);
+ }
+ E = N;
+ }
+ }
+
+ _queue_update();
+ _change_notify();
+}
+
+void VisualShader::set_graph_offset(const Vector2 &p_offset) {
+ graph_offset = p_offset;
+}
+
+Vector2 VisualShader::get_graph_offset() const {
+ return graph_offset;
+}
+
+Shader::Mode VisualShader::get_mode() const {
+ return shader_mode;
+}
+
+String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const {
+
+ Ref<VisualShaderNode> node = get_node(p_type, p_node);
+ ERR_FAIL_COND_V(!node.is_valid(), String());
+ ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_output_port_count(), String());
+ ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String());
+
+ StringBuilder global_code;
+ StringBuilder code;
+
+ global_code += String() + "shader_type canvas_item;\n";
+
+ //make it faster to go around through shader
+ VMap<ConnectionKey, const List<Connection>::Element *> input_connections;
+ VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
+
+ for (const List<Connection>::Element *E = graph[p_type].connections.front(); E; E = E->next()) {
+ ConnectionKey from_key;
+ from_key.node = E->get().from_node;
+ from_key.port = E->get().from_port;
+
+ output_connections.insert(from_key, E);
+
+ ConnectionKey to_key;
+ to_key.node = E->get().to_node;
+ to_key.port = E->get().to_port;
+
+ input_connections.insert(to_key, E);
+ }
+
+ code += "\nvoid fragment() {\n";
+
+ Set<int> processed;
+ Error err = _write_node(p_type, global_code, code, default_tex_params, input_connections, output_connections, p_node, processed, true);
+ ERR_FAIL_COND_V(err != OK, String());
+
+ if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) {
+ code += "\tCOLOR.rgb = vec3( n_out" + itos(p_node) + "p" + itos(p_port) + " );\n";
+ } else {
+ code += "\tCOLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
+ }
+ code += "}\n";
+
+ //set code secretly
+ global_code += "\n\n";
+ String final_code = global_code;
+ final_code += code;
+ return final_code;
+}
+
+#define IS_INITIAL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z'))
+
+#define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_')
+
+String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const {
+
+ String name = p_name; //validate name first
+ while (name.length() && !IS_INITIAL_CHAR(name[0])) {
+ name = name.substr(1, name.length() - 1);
+ }
+ if (name != String()) {
+
+ String valid_name;
+
+ for (int i = 0; i < name.length(); i++) {
+ if (IS_SYMBOL_CHAR(name[i])) {
+ valid_name += String::chr(name[i]);
+ } else if (name[i] == ' ') {
+ valid_name += "_";
+ }
+ }
+
+ name = valid_name;
+ }
+
+ if (name == String()) {
+ name = p_uniform->get_caption();
+ }
+
+ int attempt = 1;
+
+ while (true) {
+
+ bool exists = false;
+ for (int i = 0; i < TYPE_MAX; i++) {
+ for (const Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
+ Ref<VisualShaderNodeUniform> node = E->get().node;
+ if (node == p_uniform) { //do not test on self
+ continue;
+ }
+ if (node.is_valid() && node->get_uniform_name() == name) {
+ exists = true;
+ break;
+ }
+ }
+ if (exists) {
+ break;
+ }
+ }
+
+ if (exists) {
+ //remove numbers, put new and try again
+ attempt++;
+ while (name.length() && name[name.length() - 1] >= '0' && name[name.length() - 1] <= '9') {
+ name = name.substr(0, name.length() - 1);
+ }
+ ERR_FAIL_COND_V(name == String(), String());
+ name += itos(attempt);
+ } else {
+ break;
+ }
+ }
+
+ return name;
+}
+
+VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = {
+ { Shader::MODE_SPATIAL, "blend" },
+ { Shader::MODE_SPATIAL, "depth_draw" },
+ { Shader::MODE_SPATIAL, "cull" },
+ { Shader::MODE_SPATIAL, "diffuse" },
+ { Shader::MODE_SPATIAL, "specular" },
+ { Shader::MODE_CANVAS_ITEM, "blend" },
+ { Shader::MODE_CANVAS_ITEM, NULL }
+};
+
+static const char *type_string[VisualShader::TYPE_MAX] = {
+ "vertex",
+ "fragment",
+ "light"
+};
+bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
+
+ String name = p_name;
+ if (name == "mode") {
+ set_mode(Shader::Mode(int(p_value)));
+ return true;
+ } else if (name.begins_with("flags/")) {
+ StringName flag = name.get_slicec('/', 1);
+ bool enable = p_value;
+ if (enable) {
+ flags.insert(flag);
+ } else {
+ flags.erase(flag);
+ }
+ _queue_update();
+ return true;
+ } else if (name.begins_with("modes/")) {
+ String mode = name.get_slicec('/', 1);
+ int value = p_value;
+ if (value == 0) {
+ modes.erase(mode); //means its default anyway, so dont store it
+ } else {
+ modes[mode] = value;
+ }
+ _queue_update();
+ return true;
+ } else if (name.begins_with("nodes/")) {
+ String typestr = name.get_slicec('/', 1);
+ Type type = TYPE_VERTEX;
+ for (int i = 0; i < TYPE_MAX; i++) {
+ if (typestr == type_string[i]) {
+ type = Type(i);
+ break;
+ }
+ }
+
+ String index = name.get_slicec('/', 2);
+ if (index == "connections") {
+
+ Vector<int> conns = p_value;
+ if (conns.size() % 4 == 0) {
+ for (int i = 0; i < conns.size(); i += 4) {
+ connect_nodes(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]);
+ }
+ }
+ return true;
+ }
+
+ int id = index.to_int();
+ String what = name.get_slicec('/', 3);
+
+ if (what == "node") {
+ add_node(type, p_value, Vector2(), id);
+ return true;
+ } else if (what == "position") {
+ set_node_position(type, id, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
+
+ String name = p_name;
+ if (name == "mode") {
+ r_ret = get_mode();
+ return true;
+ } else if (name.begins_with("flags/")) {
+ StringName flag = name.get_slicec('/', 1);
+ r_ret = flags.has(flag);
+ return true;
+ } else if (name.begins_with("modes/")) {
+ String mode = name.get_slicec('/', 1);
+ if (modes.has(mode)) {
+ r_ret = modes[mode];
+ } else {
+ r_ret = 0;
+ }
+ return true;
+ } else if (name.begins_with("nodes/")) {
+ String typestr = name.get_slicec('/', 1);
+ Type type = TYPE_VERTEX;
+ for (int i = 0; i < TYPE_MAX; i++) {
+ if (typestr == type_string[i]) {
+ type = Type(i);
+ break;
+ }
+ }
+
+ String index = name.get_slicec('/', 2);
+ if (index == "connections") {
+
+ Vector<int> conns;
+ for (const List<Connection>::Element *E = graph[type].connections.front(); E; E = E->next()) {
+ conns.push_back(E->get().from_node);
+ conns.push_back(E->get().from_port);
+ conns.push_back(E->get().to_node);
+ conns.push_back(E->get().to_port);
+ }
+
+ r_ret = conns;
+ return true;
+ }
+
+ int id = index.to_int();
+ String what = name.get_slicec('/', 3);
+
+ if (what == "node") {
+ r_ret = get_node(type, id);
+ return true;
+ } else if (what == "position") {
+ r_ret = get_node_position(type, id);
+ return true;
+ }
+ }
+ return false;
+}
+void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ //mode
+ p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Spatial,CanvasItem,Particles"));
+ //render modes
+
+ Map<String, String> blend_mode_enums;
+ Set<String> toggles;
+
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) {
+
+ String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i];
+ int idx = 0;
+ bool in_enum = false;
+ while (render_mode_enums[idx].string) {
+ if (mode.begins_with(render_mode_enums[idx].string)) {
+ String begin = render_mode_enums[idx].string;
+ String option = mode.replace_first(begin + "_", "");
+ if (!blend_mode_enums.has(begin)) {
+ blend_mode_enums[begin] = option;
+ } else {
+ blend_mode_enums[begin] += "," + option;
+ }
+ in_enum = true;
+ break;
+ }
+ idx++;
+ }
+
+ if (!in_enum) {
+ toggles.insert(mode);
+ }
+ }
+
+ for (Map<String, String>::Element *E = blend_mode_enums.front(); E; E = E->next()) {
+
+ p_list->push_back(PropertyInfo(Variant::INT, "modes/" + E->key(), PROPERTY_HINT_ENUM, E->get()));
+ }
+
+ for (Set<String>::Element *E = toggles.front(); E; E = E->next()) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "flags/" + E->get()));
+ }
+
+ for (int i = 0; i < TYPE_MAX; i++) {
+ for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) {
+
+ String prop_name = "nodes/";
+ prop_name += type_string[i];
+ prop_name += "/" + itos(E->key());
+
+ if (E->key() != NODE_ID_OUTPUT) {
+
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ }
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ }
+ p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "nodes/" + String(type_string[i]) + "/connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ }
+}
+
+Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview) const {
+
+ const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
+
+ //check inputs recursively first
+ int input_count = vsnode->get_input_port_count();
+ for (int i = 0; i < input_count; i++) {
+ ConnectionKey ck;
+ ck.node = node;
+ ck.port = i;
+
+ if (input_connections.has(ck)) {
+ int from_node = input_connections[ck]->get().from_node;
+ if (processed.has(from_node)) {
+ continue;
+ }
+
+ Error err = _write_node(type, global_code, code, def_tex_params, input_connections, output_connections, from_node, processed, for_preview);
+ if (err)
+ return err;
+ }
+ }
+
+ // then this node
+
+ code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
+ Vector<String> input_vars;
+
+ input_vars.resize(vsnode->get_input_port_count());
+ String *inputs = input_vars.ptrw();
+
+ for (int i = 0; i < input_count; i++) {
+ ConnectionKey ck;
+ ck.node = node;
+ ck.port = i;
+
+ if (input_connections.has(ck)) {
+ //connected to something, use that output
+ int from_node = input_connections[ck]->get().from_node;
+ int from_port = input_connections[ck]->get().from_port;
+
+ VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i);
+ VisualShaderNode::PortType out_type = graph[type].nodes[from_node].node->get_output_port_type(from_port);
+
+ String src_var = "n_out" + itos(from_node) + "p" + itos(from_port);
+
+ if (in_type == out_type) {
+ inputs[i] = src_var;
+ } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_VECTOR) {
+ inputs[i] = "dot(" + src_var + ",vec3(0.333333,0.333333,0.333333))";
+ } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR) {
+ inputs[i] = "vec3(" + src_var + ")";
+ }
+ } else {
+
+ Variant defval = vsnode->get_input_port_default_value(i);
+ if (defval.get_type() == Variant::REAL || defval.get_type() == Variant::INT) {
+ float val = defval;
+ inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
+ } else if (defval.get_type() == Variant::VECTOR3) {
+ Vector3 val = defval;
+ inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f,%.5f,%.5f);\n", val.x, val.y, val.z);
+ } else if (defval.get_type() == Variant::TRANSFORM) {
+ Transform val = defval;
+ val.basis.transpose();
+ inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ Array values;
+ for (int i = 0; i < 3; i++) {
+ values.push_back(val.basis[i].x);
+ values.push_back(val.basis[i].y);
+ values.push_back(val.basis[i].z);
+ }
+ values.push_back(val.origin.x);
+ values.push_back(val.origin.y);
+ values.push_back(val.origin.z);
+ bool err = false;
+ code += "\tmat4 " + inputs[i] + " = " + String("mat4( vec4(%.5f,%.5f,%.5f,0.0),vec4(%.5f,%.5f,%.5f,0.0),vec4(%.5f,%.5f,%.5f,0.0),vec4(%.5f,%.5f,%.5f,1.0) );\n").sprintf(values, &err);
+ } else {
+ //will go empty, node is expected to know what it is doing at this point and handle it
+ }
+ }
+ }
+
+ int output_count = vsnode->get_output_port_count();
+ Vector<String> output_vars;
+ output_vars.resize(vsnode->get_output_port_count());
+ String *outputs = output_vars.ptrw();
+
+ for (int i = 0; i < output_count; i++) {
+
+ outputs[i] = "n_out" + itos(node) + "p" + itos(i);
+ switch (vsnode->get_output_port_type(i)) {
+ case VisualShaderNode::PORT_TYPE_SCALAR: code += String() + "\tfloat " + outputs[i] + ";\n"; break;
+ case VisualShaderNode::PORT_TYPE_VECTOR: code += String() + "\tvec3 " + outputs[i] + ";\n"; break;
+ case VisualShaderNode::PORT_TYPE_TRANSFORM: code += String() + "\tmat4 " + outputs[i] + ";\n"; break;
+ default: {}
+ }
+ }
+
+ Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
+ for (int i = 0; i < params.size(); i++) {
+ def_tex_params.push_back(params[i]);
+ }
+
+ Ref<VisualShaderNodeInput> input = vsnode;
+
+ if (input.is_valid() && for_preview) {
+ //handle for preview
+ code += input->generate_code_for_preview(type, node, inputs, outputs);
+ } else {
+ //handle normally
+ global_code += vsnode->generate_global(get_mode(), type, node);
+ code += vsnode->generate_code(get_mode(), type, node, inputs, outputs);
+ }
+ code += "\n"; //
+ processed.insert(node);
+
+ return OK;
+}
+
+void VisualShader::_update_shader() const {
+ if (!dirty)
+ return;
+
+ dirty = false;
+
+ StringBuilder global_code;
+ StringBuilder code;
+ Vector<VisualShader::DefaultTextureParam> default_tex_params;
+ static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles" };
+
+ global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
+
+ String render_mode;
+
+ {
+ //fill render mode enums
+ int idx = 0;
+ while (render_mode_enums[idx].string) {
+
+ if (shader_mode == render_mode_enums[idx].mode) {
+
+ if (modes.has(render_mode_enums[idx].string)) {
+
+ int which = modes[render_mode_enums[idx].string];
+ int count = 0;
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) {
+ String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i];
+ if (mode.begins_with(render_mode_enums[idx].string)) {
+ if (count == which) {
+ if (render_mode != String()) {
+ render_mode += ", ";
+ }
+ render_mode += mode;
+ break;
+ }
+ count++;
+ }
+ }
+ }
+ }
+ idx++;
+ }
+
+ //fill render mode flags
+ for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode)).size(); i++) {
+
+ String mode = ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader_mode))[i];
+ if (flags.has(mode)) {
+ if (render_mode != String()) {
+ render_mode += ", ";
+ }
+ render_mode += mode;
+ }
+ }
+ }
+
+ if (render_mode != String()) {
+
+ global_code += "render_mode " + render_mode + ";\n\n";
+ }
+
+ static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
+
+ for (int i = 0; i < TYPE_MAX; i++) {
+
+ //make it faster to go around through shader
+ VMap<ConnectionKey, const List<Connection>::Element *> input_connections;
+ VMap<ConnectionKey, const List<Connection>::Element *> output_connections;
+
+ for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) {
+ ConnectionKey from_key;
+ from_key.node = E->get().from_node;
+ from_key.port = E->get().from_port;
+
+ output_connections.insert(from_key, E);
+
+ ConnectionKey to_key;
+ to_key.node = E->get().to_node;
+ to_key.port = E->get().to_port;
+
+ input_connections.insert(to_key, E);
+ }
+
+ code += "\nvoid " + String(func_name[i]) + "() {\n";
+
+ Set<int> processed;
+ Error err = _write_node(Type(i), global_code, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false);
+ ERR_FAIL_COND(err != OK);
+
+ code += "}\n";
+ }
+
+ //set code secretly
+ global_code += "\n\n";
+ String final_code = global_code;
+ final_code += code;
+ const_cast<VisualShader *>(this)->set_code(final_code);
+ for (int i = 0; i < default_tex_params.size(); i++) {
+ const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param);
+ }
+}
+
+void VisualShader::_queue_update() {
+ if (dirty) {
+ return;
+ }
+
+ dirty = true;
+ call_deferred("_update_shader");
+}
+
+void VisualShader::_input_type_changed(Type p_type, int p_id) {
+ //erase connections using this input, as type changed
+ Graph *g = &graph[p_type];
+
+ for (List<Connection>::Element *E = g->connections.front(); E;) {
+ List<Connection>::Element *N = E->next();
+ if (E->get().from_node == p_id) {
+ g->connections.erase(E);
+ }
+ E = N;
+ }
+}
+
+void VisualShader::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShader::set_mode);
+
+ ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node);
+ ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position);
+
+ ClassDB::bind_method(D_METHOD("get_node", "type", "id"), &VisualShader::get_node);
+ ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position);
+
+ ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list);
+ ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id);
+
+ ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node);
+
+ ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
+ ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
+
+ ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes);
+ ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes);
+
+ ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
+
+ ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
+ ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
+
+ ClassDB::bind_method(D_METHOD("_queue_update"), &VisualShader::_queue_update);
+ ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
+
+ ClassDB::bind_method(D_METHOD("_input_type_changed"), &VisualShader::_input_type_changed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset");
+
+ BIND_ENUM_CONSTANT(TYPE_VERTEX);
+ BIND_ENUM_CONSTANT(TYPE_FRAGMENT);
+ BIND_ENUM_CONSTANT(TYPE_LIGHT);
+ BIND_ENUM_CONSTANT(TYPE_MAX);
+
+ BIND_CONSTANT(NODE_ID_INVALID);
+ BIND_CONSTANT(NODE_ID_OUTPUT);
+}
+
+VisualShader::VisualShader() {
+ shader_mode = Shader::MODE_SPATIAL;
+
+ for (int i = 0; i < TYPE_MAX; i++) {
+ Ref<VisualShaderNodeOutput> output;
+ output.instance();
+ output->shader_type = Type(i);
+ output->shader_mode = shader_mode;
+ graph[i].nodes[NODE_ID_OUTPUT].node = output;
+ graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150);
+ }
+
+ dirty = true;
+}
+
+///////////////////////////////////////////////////////////
+
+const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
+ // Spatial, Vertex
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0)" },
+
+ // Spatial, Fragment
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "float(FRONT_FACING ? 1.0 : 0.0)" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0.0)" },
+
+ // Spatial, Light
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "attenuation", "ATTENUATION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "transmission", "TRANSMISSION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(VIEWPORT_SIZE, 0.0)" },
+ // Canvas Item, Vertex
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
+
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "extra", "EXTRA_MATRIX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" },
+ // Canvas Item, Fragment
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" },
+ // Canvas Item, Light
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_vec", "vec3(LIGHT_VEC,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_height", "LIGHT_HEIGHT" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_alpha", "LIGHT_COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_uv", "vec3(LIGHT_UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow_color", "SHADOW_COLOR.rgb" },
+
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec2(POINT_COORD,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Particles, Vertex
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "index", "float(INDEX)" },
+
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL },
+};
+
+const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = {
+
+ // Spatial, Fragment
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0,1.0,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0,0.0,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "1.0" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(1.0,1.0, 0.0)" },
+
+ // Spatial, Light
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "vp_size", "vec3(1.0, 1.0, 0.0)" },
+ // Canvas Item, Vertex
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Canvas Item, Fragment
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Canvas Item, Light
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0,0.0,1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
+
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(UV,0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Particles, Vertex
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "vec3(0.0,0.0,1.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL },
+};
+
+int VisualShaderNodeInput::get_input_port_count() const {
+
+ return 0;
+}
+VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_port_type(int p_port) const {
+
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeInput::get_input_port_name(int p_port) const {
+
+ return "";
+}
+
+int VisualShaderNodeInput::get_output_port_count() const {
+
+ return 1;
+}
+VisualShaderNodeInput::PortType VisualShaderNodeInput::get_output_port_type(int p_port) const {
+
+ return get_input_type_by_name(input_name);
+}
+String VisualShaderNodeInput::get_output_port_name(int p_port) const {
+ return "";
+}
+
+String VisualShaderNodeInput::get_caption() const {
+ return TTR("Input");
+}
+
+String VisualShaderNodeInput::generate_code_for_preview(VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ int idx = 0;
+
+ String code;
+
+ while (preview_ports[idx].mode != Shader::MODE_MAX) {
+ if (preview_ports[idx].mode == shader_mode && preview_ports[idx].shader_type == shader_type && preview_ports[idx].name == input_name) {
+ code = "\t" + p_output_vars[0] + " = " + preview_ports[idx].string + ";\n";
+ break;
+ }
+ idx++;
+ }
+
+ if (code == String()) {
+ switch (get_output_port_type(0)) {
+ case PORT_TYPE_SCALAR: {
+ code = "\t" + p_output_vars[0] + " = 0.0;\n";
+ } break; //default (none found) is scalar
+ case PORT_TYPE_VECTOR: {
+ code = "\t" + p_output_vars[0] + " = vec3(0.0);\n";
+ } break; //default (none found) is scalar
+ case PORT_TYPE_TRANSFORM: {
+ code = "\t" + p_output_vars[0] + " = mat4( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), vec4(0.0,0.0,1.0,0.0), vec4(0.0,0.0,0.0,1.0) );\n";
+ } break; //default (none found) is scalar
+ }
+ }
+
+ return code;
+}
+
+String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ int idx = 0;
+
+ String code;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) {
+ code = "\t" + p_output_vars[0] + " = " + ports[idx].string + ";\n";
+ break;
+ }
+ idx++;
+ }
+
+ if (code == String()) {
+ code = "\t" + p_output_vars[0] + " = 0.0;\n"; //default (none found) is scalar
+ }
+
+ return code;
+}
+
+void VisualShaderNodeInput::set_input_name(String p_name) {
+ PortType prev_type = get_input_type_by_name(input_name);
+ input_name = p_name;
+ emit_changed();
+ if (get_input_type_by_name(input_name) != prev_type) {
+ emit_signal("input_type_changed");
+ }
+}
+
+String VisualShaderNodeInput::get_input_name() const {
+ return input_name;
+}
+
+VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_type_by_name(String p_name) const {
+
+ int idx = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == p_name) {
+ return ports[idx].type;
+ }
+ idx++;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+int VisualShaderNodeInput::get_input_index_count() const {
+ int idx = 0;
+ int count = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ count++;
+ }
+ idx++;
+ }
+
+ return count;
+}
+
+VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_index_type(int p_index) const {
+ int idx = 0;
+ int count = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ if (count == p_index) {
+ return ports[idx].type;
+ }
+ count++;
+ }
+ idx++;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeInput::get_input_index_name(int p_index) const {
+ int idx = 0;
+ int count = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ if (count == p_index) {
+ return ports[idx].name;
+ }
+ count++;
+ }
+ idx++;
+ }
+
+ return "";
+}
+
+void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "input_name") {
+ String port_list;
+
+ int idx = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ if (port_list != String()) {
+ port_list += ",";
+ }
+ port_list += ports[idx].name;
+ }
+ idx++;
+ }
+
+ if (port_list == "") {
+ port_list = TTR("None");
+ }
+ property.hint_string = port_list;
+ }
+}
+
+Vector<StringName> VisualShaderNodeInput::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("input_name");
+ return props;
+}
+
+void VisualShaderNodeInput::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_input_name", "name"), &VisualShaderNodeInput::set_input_name);
+ ClassDB::bind_method(D_METHOD("get_input_name"), &VisualShaderNodeInput::get_input_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_name", PROPERTY_HINT_ENUM, ""), "set_input_name", "get_input_name");
+ ADD_SIGNAL(MethodInfo("input_type_changed"));
+}
+VisualShaderNodeInput::VisualShaderNodeInput() {
+ input_name = "[None]";
+ // changed when set
+ shader_type = VisualShader::TYPE_MAX;
+ shader_mode = Shader::MODE_MAX;
+}
+
+////////////////////////////////////////////
+
+const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
+ // Spatial, Vertex
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "UV:xy" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "UV2:xy" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+ // Spatial, Fragment
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "emission", "EMISSION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_gloss", "CLEARCOAT_GLOSS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "anisotropy_flow", "ANISOTROPY_FLOW:xy" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "transmission", "TRANSMISSION" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor", "ALPHA_SCISSOR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" },
+
+ // Spatial, Light
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" },
+ // Canvas Item, Vertex
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX:xy" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "UV:xy" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ // Canvas Item, Fragment
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" },
+ // Canvas Item, Light
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.rgb" },
+ // Particles, Vertex
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, NULL, NULL },
+};
+
+int VisualShaderNodeOutput::get_input_port_count() const {
+
+ int idx = 0;
+ int count = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ count++;
+ }
+ idx++;
+ }
+
+ return count;
+}
+
+VisualShaderNodeOutput::PortType VisualShaderNodeOutput::get_input_port_type(int p_port) const {
+
+ int idx = 0;
+ int count = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ if (count == p_port) {
+ return ports[idx].type;
+ }
+ count++;
+ }
+ idx++;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeOutput::get_input_port_name(int p_port) const {
+
+ int idx = 0;
+ int count = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+ if (count == p_port) {
+ return String(ports[idx].name).capitalize();
+ }
+ count++;
+ }
+ idx++;
+ }
+
+ return String();
+}
+
+Variant VisualShaderNodeOutput::get_input_port_default_value(int p_port) const {
+ return Variant();
+}
+
+int VisualShaderNodeOutput::get_output_port_count() const {
+
+ return 0;
+}
+VisualShaderNodeOutput::PortType VisualShaderNodeOutput::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeOutput::get_output_port_name(int p_port) const {
+ return String();
+}
+
+bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
+
+ if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
+ String name = get_input_port_name(p_index);
+ return (name == "Normal" || name == "Rim" || name == "Alpha Scissor");
+ }
+ return false;
+}
+
+String VisualShaderNodeOutput::get_caption() const {
+ return TTR("Output");
+}
+
+String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ int idx = 0;
+ int count = 0;
+
+ String code;
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
+
+ if (p_input_vars[count] != String()) {
+ String s = ports[idx].string;
+ if (s.find(":") != -1) {
+ code += "\t" + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n";
+ } else {
+ code += "\t" + s + " = " + p_input_vars[count] + ";\n";
+ }
+ }
+ count++;
+ }
+ idx++;
+ }
+
+ return code;
+}
+
+VisualShaderNodeOutput::VisualShaderNodeOutput() {
+}
+
+///////////////////////////
+
+void VisualShaderNodeUniform::set_uniform_name(const String &p_name) {
+ uniform_name = p_name;
+ emit_signal("name_changed");
+ emit_changed();
+}
+
+String VisualShaderNodeUniform::get_uniform_name() const {
+ return uniform_name;
+}
+
+void VisualShaderNodeUniform::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name);
+ ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "uniform_name"), "set_uniform_name", "get_uniform_name");
+}
+
+VisualShaderNodeUniform::VisualShaderNodeUniform() {
+}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
new file mode 100644
index 0000000000..81dd37de3c
--- /dev/null
+++ b/scene/resources/visual_shader.h
@@ -0,0 +1,314 @@
+/*************************************************************************/
+/* visual_shader.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 VISUAL_SHADER_H
+#define VISUAL_SHADER_H
+
+#include "scene/resources/shader.h"
+#include "string_builder.h"
+
+class VisualShaderNodeUniform;
+class VisualShaderNode;
+
+class VisualShader : public Shader {
+ GDCLASS(VisualShader, Shader)
+public:
+ enum Type {
+ TYPE_VERTEX,
+ TYPE_FRAGMENT,
+ TYPE_LIGHT,
+ TYPE_MAX
+ };
+
+ struct Connection {
+ int from_node;
+ int from_port;
+ int to_node;
+ int to_port;
+ };
+
+ struct DefaultTextureParam {
+ StringName name;
+ Ref<Texture> param;
+ };
+
+private:
+ struct Node {
+ Ref<VisualShaderNode> node;
+ Vector2 position;
+ };
+
+ struct Graph {
+ Map<int, Node> nodes;
+ List<Connection> connections;
+ } graph[TYPE_MAX];
+
+ Shader::Mode shader_mode;
+
+ Array _get_node_connections(Type p_type) const;
+
+ Vector2 graph_offset;
+
+ struct RenderModeEnums {
+ Shader::Mode mode;
+ const char *string;
+ };
+
+ HashMap<String, int> modes;
+ Set<StringName> flags;
+
+ static RenderModeEnums render_mode_enums[];
+
+ volatile mutable bool dirty;
+ void _queue_update();
+
+ union ConnectionKey {
+
+ struct {
+ uint64_t node : 32;
+ uint64_t port : 32;
+ };
+ uint64_t key;
+ bool operator<(const ConnectionKey &p_key) const {
+ return key < p_key.key;
+ }
+ };
+
+ Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview) const;
+
+ void _input_type_changed(Type p_type, int p_id);
+
+protected:
+ virtual void _update_shader() const;
+ static void _bind_methods();
+
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ enum {
+ NODE_ID_INVALID = -1,
+ NODE_ID_OUTPUT = 0,
+ };
+
+ void add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id);
+ void set_node_position(Type p_type, int p_id, const Vector2 &p_position);
+
+ Vector2 get_node_position(Type p_type, int p_id) const;
+ Ref<VisualShaderNode> get_node(Type p_type, int p_id) const;
+
+ Vector<int> get_node_list(Type p_type) const;
+ int get_valid_node_id(Type p_type) const;
+
+ int find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const;
+ void remove_node(Type p_type, int p_id);
+
+ bool is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
+ bool can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
+ Error connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
+ void disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
+
+ void get_node_connections(Type p_type, List<Connection> *r_connections) const;
+
+ void set_mode(Mode p_mode);
+ virtual Mode get_mode() const;
+
+ void set_graph_offset(const Vector2 &p_offset);
+ Vector2 get_graph_offset() const;
+
+ String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const;
+
+ String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const;
+
+ VisualShader();
+};
+
+VARIANT_ENUM_CAST(VisualShader::Type)
+///
+///
+///
+
+class VisualShaderNode : public Resource {
+ GDCLASS(VisualShaderNode, Resource)
+
+ int port_preview;
+
+ Map<int, Variant> default_input_values;
+
+ Array _get_default_input_values() const;
+ void _set_default_input_values(const Array &p_values);
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum PortType {
+ PORT_TYPE_SCALAR,
+ PORT_TYPE_VECTOR,
+ PORT_TYPE_TRANSFORM,
+ };
+
+ virtual String get_caption() const = 0;
+
+ virtual int get_input_port_count() const = 0;
+ virtual PortType get_input_port_type(int p_port) const = 0;
+ virtual String get_input_port_name(int p_port) const = 0;
+
+ void set_input_port_default_value(int p_port, const Variant &p_value);
+ Variant get_input_port_default_value(int p_port) const; // if NIL (default if node does not set anything) is returned, it means no default value is wanted if disconnected, thus no input var must be supplied (empty string will be supplied)
+
+ virtual int get_output_port_count() const = 0;
+ virtual PortType get_output_port_type(int p_port) const = 0;
+ virtual String get_output_port_name(int p_port) const = 0;
+
+ void set_output_port_for_preview(int p_index);
+ int get_output_port_for_preview() const;
+
+ virtual bool is_port_separator(int p_index) const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const = 0; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const;
+
+ VisualShaderNode();
+};
+/////
+
+class VisualShaderNodeInput : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeInput, VisualShaderNode)
+
+ friend class VisualShader;
+ VisualShader::Type shader_type;
+ Shader::Mode shader_mode;
+
+ struct Port {
+ Shader::Mode mode;
+ VisualShader::Type shader_type;
+ PortType type;
+ const char *name;
+ const char *string;
+ };
+
+ static const Port ports[];
+ static const Port preview_ports[];
+
+ String input_name;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String get_caption() const;
+
+ virtual String generate_code_for_preview(VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const;
+
+ void set_input_name(String p_name);
+ String get_input_name() const;
+
+ int get_input_index_count() const;
+ PortType get_input_index_type(int p_index) const;
+ String get_input_index_name(int p_index) const;
+
+ PortType get_input_type_by_name(String p_name) const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeInput();
+};
+
+///
+
+class VisualShaderNodeOutput : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeOutput, VisualShaderNode)
+public:
+ friend class VisualShader;
+ VisualShader::Type shader_type;
+ Shader::Mode shader_mode;
+
+ struct Port {
+ Shader::Mode mode;
+ VisualShader::Type shader_type;
+ PortType type;
+ const char *name;
+ const char *string;
+ };
+
+ static const Port ports[];
+
+public:
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+ Variant get_input_port_default_value(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual bool is_port_separator(int p_index) const;
+
+ virtual String get_caption() const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const;
+
+ VisualShaderNodeOutput();
+};
+
+class VisualShaderNodeUniform : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUniform, VisualShaderNode)
+
+ String uniform_name;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_uniform_name(const String &p_name);
+ String get_uniform_name() const;
+
+ VisualShaderNodeUniform();
+};
+
+#endif // VISUAL_SHADER_H
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
new file mode 100644
index 0000000000..d011b102a2
--- /dev/null
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -0,0 +1,1926 @@
+/*************************************************************************/
+/* visual_shader_nodes.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 "visual_shader_nodes.h"
+////////////// Scalar
+
+String VisualShaderNodeScalarConstant::get_caption() const {
+ return "Scalar";
+}
+
+int VisualShaderNodeScalarConstant::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeScalarConstant::PortType VisualShaderNodeScalarConstant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarConstant::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeScalarConstant::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeScalarConstant::PortType VisualShaderNodeScalarConstant::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarConstant::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeScalarConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = " + vformat("%.6f", constant) + ";\n";
+}
+
+void VisualShaderNodeScalarConstant::set_constant(float p_value) {
+
+ constant = p_value;
+ emit_changed();
+}
+
+float VisualShaderNodeScalarConstant::get_constant() const {
+
+ return constant;
+}
+
+Vector<StringName> VisualShaderNodeScalarConstant::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("constant");
+ return props;
+}
+
+void VisualShaderNodeScalarConstant::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeScalarConstant::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeScalarConstant::get_constant);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant"), "set_constant", "get_constant");
+}
+
+VisualShaderNodeScalarConstant::VisualShaderNodeScalarConstant() {
+ constant = 0;
+}
+
+////////////// Color
+
+String VisualShaderNodeColorConstant::get_caption() const {
+ return "Color";
+}
+
+int VisualShaderNodeColorConstant::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeColorConstant::get_output_port_count() const {
+ return 2;
+}
+VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_output_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const {
+ return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeColorConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ String code;
+ code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f,%.6f,%.6f)", constant.r, constant.g, constant.b) + ";\n";
+ code += "\t" + p_output_vars[1] + " = " + vformat("%.6f", constant.a) + ";\n";
+
+ return code;
+}
+
+void VisualShaderNodeColorConstant::set_constant(Color p_value) {
+
+ constant = p_value;
+ emit_changed();
+}
+
+Color VisualShaderNodeColorConstant::get_constant() const {
+
+ return constant;
+}
+
+Vector<StringName> VisualShaderNodeColorConstant::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("constant");
+ return props;
+}
+
+void VisualShaderNodeColorConstant::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeColorConstant::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeColorConstant::get_constant);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "constant"), "set_constant", "get_constant");
+}
+
+VisualShaderNodeColorConstant::VisualShaderNodeColorConstant() {
+ constant = Color(1, 1, 1, 1);
+}
+
+////////////// Vector
+
+String VisualShaderNodeVec3Constant::get_caption() const {
+ return "Vector";
+}
+
+int VisualShaderNodeVec3Constant::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVec3Constant::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeVec3Constant::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVec3Constant::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeVec3Constant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f,%.6f,%.6f)", constant.x, constant.y, constant.z) + ";\n";
+}
+
+void VisualShaderNodeVec3Constant::set_constant(Vector3 p_value) {
+
+ constant = p_value;
+ emit_changed();
+}
+
+Vector3 VisualShaderNodeVec3Constant::get_constant() const {
+
+ return constant;
+}
+
+Vector<StringName> VisualShaderNodeVec3Constant::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("constant");
+ return props;
+}
+
+void VisualShaderNodeVec3Constant::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeVec3Constant::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeVec3Constant::get_constant);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant"), "set_constant", "get_constant");
+}
+
+VisualShaderNodeVec3Constant::VisualShaderNodeVec3Constant() {
+}
+
+////////////// Transform
+
+String VisualShaderNodeTransformConstant::get_caption() const {
+ return "Transform";
+}
+
+int VisualShaderNodeTransformConstant::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeTransformConstant::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeTransformConstant::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+String VisualShaderNodeTransformConstant::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ Transform t = constant;
+ t.basis.transpose();
+
+ String code = "\t" + p_output_vars[0] + " = mat4(";
+ code += vformat("vec4(%.6f,%.6f,%.6f,0.0),", t.basis[0].x, t.basis[0].y, t.basis[0].z);
+ code += vformat("vec4(%.6f,%.6f,%.6f,0.0),", t.basis[1].x, t.basis[1].y, t.basis[1].z);
+ code += vformat("vec4(%.6f,%.6f,%.6f,0.0),", t.basis[2].x, t.basis[2].y, t.basis[2].z);
+ code += vformat("vec4(%.6f,%.6f,%.6f,1.0) );\n", t.origin.x, t.origin.y, t.origin.z);
+ return code;
+}
+
+void VisualShaderNodeTransformConstant::set_constant(Transform p_value) {
+
+ constant = p_value;
+ emit_changed();
+}
+
+Transform VisualShaderNodeTransformConstant::get_constant() const {
+
+ return constant;
+}
+
+Vector<StringName> VisualShaderNodeTransformConstant::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("constant");
+ return props;
+}
+
+void VisualShaderNodeTransformConstant::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeTransformConstant::set_constant);
+ ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeTransformConstant::get_constant);
+
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "constant"), "set_constant", "get_constant");
+}
+
+VisualShaderNodeTransformConstant::VisualShaderNodeTransformConstant() {
+}
+
+////////////// Texture
+
+String VisualShaderNodeTexture::get_caption() const {
+ return "Texture";
+}
+
+int VisualShaderNodeTexture::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_input_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeTexture::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "uv" : "lod";
+}
+
+int VisualShaderNodeTexture::get_output_port_count() const {
+ return 2;
+}
+VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_output_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeTexture::get_output_port_name(int p_port) const {
+ return p_port == 0 ? "rgb" : "alpha";
+}
+
+static String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) {
+
+ static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt" };
+ return p_name + "_" + String(typepf[p_type]) + "_" + itos(p_id);
+}
+
+Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
+ VisualShader::DefaultTextureParam dtp;
+ dtp.name = make_unique_id(p_type, p_id, "tex");
+ dtp.param = texture;
+ Vector<VisualShader::DefaultTextureParam> ret;
+ ret.push_back(dtp);
+ return ret;
+}
+
+String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+
+ if (source == SOURCE_TEXTURE) {
+
+ String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "tex");
+ switch (texture_type) {
+ case TYPE_DATA: break;
+ case TYPE_COLOR: u += " : hint_color"; break;
+ case TYPE_NORMALMAP: u += " : hint_normal"; break;
+ }
+ return u + ";";
+ }
+
+ return String();
+}
+
+String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ if (source == SOURCE_TEXTURE) {
+ String id = make_unique_id(p_type, p_id, "tex");
+ String code;
+ if (p_input_vars[0] == String()) { //none bound, do nothing
+
+ code += "\tvec4 " + id + "_read = vec4(0.0);\n";
+
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\tvec4 " + id + "_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n";
+ } else {
+ code += "\tvec4 " + id + "_read = textureLod( " + id + " , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n";
+ code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n";
+ return code;
+ }
+
+ if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+
+ String code = "\t{\n";
+ if (p_input_vars[0] == String()) { //none bound, do nothing
+
+ code += "\t\tvec4 _tex_read = vec4(0.0);\n";
+
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy, 0.0 );\n";
+ } else {
+ code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n";
+ code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n";
+ code += "\t}\n";
+ return code;
+ }
+
+ if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
+
+ String code = "\t{\n";
+ if (p_input_vars[0] == String()) { //none bound, do nothing
+
+ code += "\t\tvec4 _tex_read = vec4(0.0);\n";
+
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\t\tvec4 _tex_read = texture( TEXTURE , " + p_input_vars[0] + ".xy );\n";
+ } else {
+ code += "\t\tvec4 _tex_read = textureLod( TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n";
+ code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n";
+ code += "\t}\n";
+ return code;
+ }
+
+ if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
+
+ String code = "\t{\n";
+ if (p_input_vars[0] == String()) { //none bound, do nothing
+
+ code += "\t\tvec4 _tex_read = vec4(0.0);\n";
+
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\t\tvec4 _tex_read = texture( NORMAL_TEXTURE , " + p_input_vars[0] + ".xy );\n";
+ } else {
+ code += "\t\tvec4 _tex_read = textureLod( NORMAL_TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t\t" + p_output_vars[0] + " = _tex_read.rgb;\n";
+ code += "\t\t" + p_output_vars[1] + " = _tex_read.a;\n";
+ code += "\t}\n";
+ return code;
+ }
+
+ //none
+ String code;
+ code += "\t" + p_output_vars[0] + " = vec3(0.0);\n";
+ code += "\t" + p_output_vars[1] + " = 1.0;\n";
+ return code;
+}
+
+void VisualShaderNodeTexture::set_source(Source p_source) {
+ source = p_source;
+ emit_changed();
+ emit_signal("editor_refresh_request");
+}
+
+VisualShaderNodeTexture::Source VisualShaderNodeTexture::get_source() const {
+ return source;
+}
+
+void VisualShaderNodeTexture::set_texture(Ref<Texture> p_value) {
+
+ texture = p_value;
+ emit_changed();
+}
+
+Ref<Texture> VisualShaderNodeTexture::get_texture() const {
+
+ return texture;
+}
+
+void VisualShaderNodeTexture::set_texture_type(TextureType p_type) {
+ texture_type = p_type;
+ emit_changed();
+}
+
+VisualShaderNodeTexture::TextureType VisualShaderNodeTexture::get_texture_type() const {
+ return texture_type;
+}
+
+Vector<StringName> VisualShaderNodeTexture::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("source");
+ if (source == SOURCE_TEXTURE) {
+ props.push_back("texture");
+ props.push_back("texture_type");
+ }
+ return props;
+}
+
+String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const {
+
+ if (source == SOURCE_TEXTURE) {
+ return String(); // all good
+ }
+
+ if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+
+ return String(); // all good
+ }
+
+ if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
+
+ return String(); // all good
+ }
+
+ if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM) {
+
+ return String(); // all good
+ }
+
+ return TTR("Invalid source for shader.");
+}
+
+void VisualShaderNodeTexture::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_source", "value"), &VisualShaderNodeTexture::set_source);
+ ClassDB::bind_method(D_METHOD("get_source"), &VisualShaderNodeTexture::get_source);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "value"), &VisualShaderNodeTexture::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeTexture::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type);
+ ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D"), "set_source", "get_source");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type");
+
+ BIND_ENUM_CONSTANT(SOURCE_TEXTURE);
+ BIND_ENUM_CONSTANT(SOURCE_SCREEN);
+ BIND_ENUM_CONSTANT(SOURCE_2D_TEXTURE);
+ BIND_ENUM_CONSTANT(SOURCE_2D_NORMAL);
+ BIND_ENUM_CONSTANT(TYPE_DATA);
+ BIND_ENUM_CONSTANT(TYPE_COLOR);
+ BIND_ENUM_CONSTANT(TYPE_NORMALMAP);
+}
+
+VisualShaderNodeTexture::VisualShaderNodeTexture() {
+ texture_type = TYPE_DATA;
+ source = SOURCE_TEXTURE;
+}
+
+////////////// CubeMap
+
+String VisualShaderNodeCubeMap::get_caption() const {
+ return "CubeMap";
+}
+
+int VisualShaderNodeCubeMap::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeCubeMap::PortType VisualShaderNodeCubeMap::get_input_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeCubeMap::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "uv" : "lod";
+}
+
+int VisualShaderNodeCubeMap::get_output_port_count() const {
+ return 2;
+}
+VisualShaderNodeCubeMap::PortType VisualShaderNodeCubeMap::get_output_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeCubeMap::get_output_port_name(int p_port) const {
+ return p_port == 0 ? "rgb" : "alpha";
+}
+
+Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCubeMap::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
+ VisualShader::DefaultTextureParam dtp;
+ dtp.name = make_unique_id(p_type, p_id, "cube");
+ dtp.param = cube_map;
+ Vector<VisualShader::DefaultTextureParam> ret;
+ ret.push_back(dtp);
+ return ret;
+}
+
+String VisualShaderNodeCubeMap::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+
+ String u = "uniform sampler2DCube " + make_unique_id(p_type, p_id, "cube");
+ switch (texture_type) {
+ case TYPE_DATA: break;
+ case TYPE_COLOR: u += " : hint_color"; break;
+ case TYPE_NORMALMAP: u += " : hint_normal"; break;
+ }
+ return u + ";";
+}
+
+String VisualShaderNodeCubeMap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ String id = make_unique_id(p_type, p_id, "cube");
+ String code;
+ if (p_input_vars[0] == String()) { //none bound, do nothing
+
+ code += "\tvec4 " + id + "_read = vec4(0.0);\n";
+
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\tvec4 " + id + "_read = texture( " + id + " , " + p_input_vars[0] + " );\n";
+ } else {
+ code += "\tvec4 " + id + "_read = textureLod( " + id + " , " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n";
+ code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n";
+ return code;
+}
+
+void VisualShaderNodeCubeMap::set_cube_map(Ref<CubeMap> p_value) {
+
+ cube_map = p_value;
+ emit_changed();
+}
+
+Ref<CubeMap> VisualShaderNodeCubeMap::get_cube_map() const {
+
+ return cube_map;
+}
+
+void VisualShaderNodeCubeMap::set_texture_type(TextureType p_type) {
+ texture_type = p_type;
+ emit_changed();
+}
+
+VisualShaderNodeCubeMap::TextureType VisualShaderNodeCubeMap::get_texture_type() const {
+ return texture_type;
+}
+
+Vector<StringName> VisualShaderNodeCubeMap::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("cube_map");
+ props.push_back("texture_type");
+ return props;
+}
+
+void VisualShaderNodeCubeMap::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_cube_map", "value"), &VisualShaderNodeCubeMap::set_cube_map);
+ ClassDB::bind_method(D_METHOD("get_cube_map"), &VisualShaderNodeCubeMap::get_cube_map);
+
+ ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeCubeMap::set_texture_type);
+ ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeCubeMap::get_texture_type);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "cube_map", PROPERTY_HINT_RESOURCE_TYPE, "CubeMap"), "set_cube_map", "get_cube_map");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type");
+
+ BIND_ENUM_CONSTANT(TYPE_DATA);
+ BIND_ENUM_CONSTANT(TYPE_COLOR);
+ BIND_ENUM_CONSTANT(TYPE_NORMALMAP);
+}
+
+VisualShaderNodeCubeMap::VisualShaderNodeCubeMap() {
+ texture_type = TYPE_DATA;
+}
+////////////// Scalar Op
+
+String VisualShaderNodeScalarOp::get_caption() const {
+ return "ScalarOp";
+}
+
+int VisualShaderNodeScalarOp::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeScalarOp::PortType VisualShaderNodeScalarOp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarOp::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "a" : "b";
+}
+
+int VisualShaderNodeScalarOp::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeScalarOp::PortType VisualShaderNodeScalarOp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarOp::get_output_port_name(int p_port) const {
+ return "op"; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeScalarOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ String code = "\t" + p_output_vars[0] + " = ";
+ switch (op) {
+
+ case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; break;
+ case OP_SUB: code += p_input_vars[0] + " - " + p_input_vars[1] + ";\n"; break;
+ case OP_MUL: code += p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; break;
+ case OP_DIV: code += p_input_vars[0] + " / " + p_input_vars[1] + ";\n"; break;
+ case OP_MOD: code += "mod( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_POW: code += "pow( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_ATAN2: code += "atan( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ }
+
+ return code;
+}
+
+void VisualShaderNodeScalarOp::set_operator(Operator p_op) {
+
+ op = p_op;
+ emit_changed();
+}
+
+VisualShaderNodeScalarOp::Operator VisualShaderNodeScalarOp::get_operator() const {
+
+ return op;
+}
+
+Vector<StringName> VisualShaderNodeScalarOp::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("operator");
+ return props;
+}
+
+void VisualShaderNodeScalarOp::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeScalarOp::set_operator);
+ ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeScalarOp::get_operator);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Atan2"), "set_operator", "get_operator");
+
+ BIND_ENUM_CONSTANT(OP_ADD);
+ BIND_ENUM_CONSTANT(OP_SUB);
+ BIND_ENUM_CONSTANT(OP_MUL);
+ BIND_ENUM_CONSTANT(OP_DIV);
+ BIND_ENUM_CONSTANT(OP_MOD);
+ BIND_ENUM_CONSTANT(OP_POW);
+ BIND_ENUM_CONSTANT(OP_MAX);
+ BIND_ENUM_CONSTANT(OP_MIN);
+ BIND_ENUM_CONSTANT(OP_ATAN2);
+}
+
+VisualShaderNodeScalarOp::VisualShaderNodeScalarOp() {
+ op = OP_ADD;
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+}
+
+////////////// Vector Op
+
+String VisualShaderNodeVectorOp::get_caption() const {
+ return "VectorOp";
+}
+
+int VisualShaderNodeVectorOp::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeVectorOp::PortType VisualShaderNodeVectorOp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorOp::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "a" : "b";
+}
+
+int VisualShaderNodeVectorOp::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorOp::PortType VisualShaderNodeVectorOp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorOp::get_output_port_name(int p_port) const {
+ return "op"; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ String code = "\t" + p_output_vars[0] + " = ";
+ switch (op) {
+
+ case OP_ADD: code += p_input_vars[0] + " + " + p_input_vars[1] + ";\n"; break;
+ case OP_SUB: code += p_input_vars[0] + " - " + p_input_vars[1] + ";\n"; break;
+ case OP_MUL: code += p_input_vars[0] + " * " + p_input_vars[1] + ";\n"; break;
+ case OP_DIV: code += p_input_vars[0] + " / " + p_input_vars[1] + ";\n"; break;
+ case OP_MOD: code += "mod( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_POW: code += "pow( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_MAX: code += "max( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_MIN: code += "min( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ case OP_CROSS: code += "cross( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n"; break;
+ }
+
+ return code;
+}
+
+void VisualShaderNodeVectorOp::set_operator(Operator p_op) {
+
+ op = p_op;
+ emit_changed();
+}
+
+VisualShaderNodeVectorOp::Operator VisualShaderNodeVectorOp::get_operator() const {
+
+ return op;
+}
+
+Vector<StringName> VisualShaderNodeVectorOp::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("operator");
+ return props;
+}
+
+void VisualShaderNodeVectorOp::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeVectorOp::set_operator);
+ ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeVectorOp::get_operator);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Add,Sub,Multiply,Divide,Remainder,Power,Max,Min,Cross"), "set_operator", "get_operator");
+
+ BIND_ENUM_CONSTANT(OP_ADD);
+ BIND_ENUM_CONSTANT(OP_SUB);
+ BIND_ENUM_CONSTANT(OP_MUL);
+ BIND_ENUM_CONSTANT(OP_DIV);
+ BIND_ENUM_CONSTANT(OP_MOD);
+ BIND_ENUM_CONSTANT(OP_POW);
+ BIND_ENUM_CONSTANT(OP_MAX);
+ BIND_ENUM_CONSTANT(OP_MIN);
+ BIND_ENUM_CONSTANT(OP_CROSS);
+}
+
+VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() {
+ op = OP_ADD;
+ set_input_port_default_value(0, Vector3());
+ set_input_port_default_value(1, Vector3());
+}
+
+////////////// Color Op
+
+String VisualShaderNodeColorOp::get_caption() const {
+ return "ColorOp";
+}
+
+int VisualShaderNodeColorOp::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeColorOp::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "a" : "b";
+}
+
+int VisualShaderNodeColorOp::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeColorOp::get_output_port_name(int p_port) const {
+ return "op"; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeColorOp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ String code;
+ static const char *axisn[3] = { "x", "y", "z" };
+ switch (op) {
+ case OP_SCREEN: {
+
+ code += "\t" + p_output_vars[0] + "=vec3(1.0)-(vec3(1.0)-" + p_input_vars[0] + ")*(vec3(1.0)-" + p_input_vars[1] + ");\n";
+ } break;
+ case OP_DIFFERENCE: {
+
+ code += "\t" + p_output_vars[0] + "=abs(" + p_input_vars[0] + "-" + p_input_vars[1] + ");\n";
+ } break;
+ case OP_DARKEN: {
+
+ code += "\t" + p_output_vars[0] + "=min(" + p_input_vars[0] + "," + p_input_vars[1] + ");\n";
+ } break;
+ case OP_LIGHTEN: {
+
+ code += "\t" + p_output_vars[0] + "=max(" + p_input_vars[0] + "," + p_input_vars[1] + ");\n";
+
+ } break;
+ case OP_OVERLAY: {
+
+ for (int i = 0; i < 3; i++) {
+ code += "\t{\n";
+ code += "\t\tfloat base=" + p_input_vars[0] + "." + axisn[i] + ";\n";
+ code += "\t\tfloat blend=" + p_input_vars[1] + "." + axisn[i] + ";\n";
+ code += "\t\tif (base < 0.5) {\n";
+ code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = 2.0 * base * blend;\n";
+ code += "\t\t} else {\n";
+ code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ }
+
+ } break;
+ case OP_DODGE: {
+
+ code += "\t" + p_output_vars[0] + "=(" + p_input_vars[0] + ")/(vec3(1.0)-" + p_input_vars[1] + ");\n";
+
+ } break;
+ case OP_BURN: {
+
+ code += "\t" + p_output_vars[0] + "=vec3(1.0)-(vec3(1.0)-" + p_input_vars[0] + ")/(" + p_input_vars[1] + ");\n";
+ } break;
+ case OP_SOFT_LIGHT: {
+
+ for (int i = 0; i < 3; i++) {
+ code += "\t{\n";
+ code += "\t\tfloat base=" + p_input_vars[0] + "." + axisn[i] + ";\n";
+ code += "\t\tfloat blend=" + p_input_vars[1] + "." + axisn[i] + ";\n";
+ code += "\t\tif (base < 0.5) {\n";
+ code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (base * (blend+0.5));\n";
+ code += "\t\t} else {\n";
+ code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0-base) * (1.0-(blend-0.5)));\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ }
+
+ } break;
+ case OP_HARD_LIGHT: {
+
+ for (int i = 0; i < 3; i++) {
+ code += "\t{\n";
+ code += "\t\tfloat base=" + p_input_vars[0] + "." + axisn[i] + ";\n";
+ code += "\t\tfloat blend=" + p_input_vars[1] + "." + axisn[i] + ";\n";
+ code += "\t\tif (base < 0.5) {\n";
+ code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (base * (2.0*blend));\n";
+ code += "\t\t} else {\n";
+ code += "\t\t\t" + p_output_vars[0] + "." + axisn[i] + " = (1.0 - (1.0-base) * (1.0-2.0*(blend-0.5)));\n";
+ code += "\t\t}\n";
+ code += "\t}\n";
+ }
+
+ } break;
+ }
+
+ return code;
+}
+
+void VisualShaderNodeColorOp::set_operator(Operator p_op) {
+
+ op = p_op;
+ emit_changed();
+}
+
+VisualShaderNodeColorOp::Operator VisualShaderNodeColorOp::get_operator() const {
+
+ return op;
+}
+
+Vector<StringName> VisualShaderNodeColorOp::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("operator");
+ return props;
+}
+
+void VisualShaderNodeColorOp::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeColorOp::set_operator);
+ ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeColorOp::get_operator);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "Screen,Difference,Darken,Lighten,Overlay,Dodge,Burn,SoftLight,HardLight"), "set_operator", "get_operator");
+
+ BIND_ENUM_CONSTANT(OP_SCREEN);
+ BIND_ENUM_CONSTANT(OP_DIFFERENCE);
+ BIND_ENUM_CONSTANT(OP_DARKEN);
+ BIND_ENUM_CONSTANT(OP_LIGHTEN);
+ BIND_ENUM_CONSTANT(OP_OVERLAY);
+ BIND_ENUM_CONSTANT(OP_DODGE);
+ BIND_ENUM_CONSTANT(OP_BURN);
+ BIND_ENUM_CONSTANT(OP_SOFT_LIGHT);
+ BIND_ENUM_CONSTANT(OP_HARD_LIGHT);
+}
+
+VisualShaderNodeColorOp::VisualShaderNodeColorOp() {
+ op = OP_SCREEN;
+ set_input_port_default_value(0, Vector3());
+ set_input_port_default_value(1, Vector3());
+}
+
+////////////// Transform Mult
+
+String VisualShaderNodeTransformMult::get_caption() const {
+ return "TransformMult";
+}
+
+int VisualShaderNodeTransformMult::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeTransformMult::PortType VisualShaderNodeTransformMult::get_input_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+String VisualShaderNodeTransformMult::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "a" : "b";
+}
+
+int VisualShaderNodeTransformMult::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeTransformMult::PortType VisualShaderNodeTransformMult::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+String VisualShaderNodeTransformMult::get_output_port_name(int p_port) const {
+ return "mult"; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeTransformMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ if (op == OP_AxB) {
+ return "\t" + p_output_vars[0] + " = " + p_input_vars[0] + " * " + p_input_vars[1] + ";\n";
+ } else {
+ return "\t" + p_output_vars[0] + " = " + p_input_vars[1] + " * " + p_input_vars[0] + ";\n";
+ }
+}
+
+void VisualShaderNodeTransformMult::set_operator(Operator p_op) {
+
+ op = p_op;
+ emit_changed();
+}
+
+VisualShaderNodeTransformMult::Operator VisualShaderNodeTransformMult::get_operator() const {
+
+ return op;
+}
+
+Vector<StringName> VisualShaderNodeTransformMult::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("operator");
+ return props;
+}
+
+void VisualShaderNodeTransformMult::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeTransformMult::set_operator);
+ ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeTransformMult::get_operator);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A"), "set_operator", "get_operator");
+
+ BIND_ENUM_CONSTANT(OP_AxB);
+ BIND_ENUM_CONSTANT(OP_BxA);
+}
+
+VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() {
+ op = OP_AxB;
+ set_input_port_default_value(0, Transform());
+ set_input_port_default_value(1, Transform());
+}
+
+////////////// TransformVec Mult
+
+String VisualShaderNodeTransformVecMult::get_caption() const {
+ return "TransformVectorMult";
+}
+
+int VisualShaderNodeTransformVecMult::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_input_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_TRANSFORM : PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeTransformVecMult::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "a" : "b";
+}
+
+int VisualShaderNodeTransformVecMult::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeTransformVecMult::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeTransformVecMult::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ if (op == OP_AxB) {
+ return "\t" + p_output_vars[0] + " = ( " + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 1.0) ).xyz;\n";
+ } else if (op == OP_BxA) {
+ return "\t" + p_output_vars[0] + " = ( vec4(" + p_input_vars[1] + ", 1.0) * " + p_input_vars[0] + " ).xyz;\n";
+ } else if (op == OP_3x3_AxB) {
+ return "\t" + p_output_vars[0] + " = ( " + p_input_vars[0] + " * vec4(" + p_input_vars[1] + ", 0.0) ).xyz;\n";
+ } else {
+ return "\t" + p_output_vars[0] + " = ( vec4(" + p_input_vars[1] + ", 0.0) * " + p_input_vars[0] + " ).xyz;\n";
+ }
+}
+
+void VisualShaderNodeTransformVecMult::set_operator(Operator p_op) {
+
+ op = p_op;
+ emit_changed();
+}
+
+VisualShaderNodeTransformVecMult::Operator VisualShaderNodeTransformVecMult::get_operator() const {
+
+ return op;
+}
+
+Vector<StringName> VisualShaderNodeTransformVecMult::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("operator");
+ return props;
+}
+
+void VisualShaderNodeTransformVecMult::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeTransformVecMult::set_operator);
+ ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeTransformVecMult::get_operator);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, "A x B,B x A,A x B (3x3),B x A (3x3)"), "set_operator", "get_operator");
+
+ BIND_ENUM_CONSTANT(OP_AxB);
+ BIND_ENUM_CONSTANT(OP_BxA);
+ BIND_ENUM_CONSTANT(OP_3x3_AxB);
+ BIND_ENUM_CONSTANT(OP_3x3_BxA);
+}
+
+VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() {
+ op = OP_AxB;
+ set_input_port_default_value(0, Transform());
+ set_input_port_default_value(1, Vector3());
+}
+
+////////////// Scalar Func
+
+String VisualShaderNodeScalarFunc::get_caption() const {
+ return "ScalarFunc";
+}
+
+int VisualShaderNodeScalarFunc::get_input_port_count() const {
+ return 1;
+}
+VisualShaderNodeScalarFunc::PortType VisualShaderNodeScalarFunc::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarFunc::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeScalarFunc::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeScalarFunc::PortType VisualShaderNodeScalarFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ static const char *scalar_func_id[FUNC_NEGATE + 1] = {
+ "sin($)",
+ "cos($)",
+ "tan($)",
+ "asin($)",
+ "acos($)",
+ "atan($)",
+ "sinh($)",
+ "cosh($)",
+ "tanh($)",
+ "log($)",
+ "exp($)",
+ "sqrt($)",
+ "abs($)",
+ "sign($)",
+ "floor($)",
+ "round($)",
+ "ceil($)",
+ "fract($)",
+ "min(max($,0),1)",
+ "-($)",
+ };
+
+ return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n";
+}
+
+void VisualShaderNodeScalarFunc::set_function(Function p_func) {
+
+ func = p_func;
+ emit_changed();
+}
+
+VisualShaderNodeScalarFunc::Function VisualShaderNodeScalarFunc::get_function() const {
+
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeScalarFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeScalarFunc::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_SIN);
+ BIND_ENUM_CONSTANT(FUNC_COS);
+ BIND_ENUM_CONSTANT(FUNC_TAN);
+ BIND_ENUM_CONSTANT(FUNC_ASIN);
+ BIND_ENUM_CONSTANT(FUNC_ACOS);
+ BIND_ENUM_CONSTANT(FUNC_ATAN);
+ BIND_ENUM_CONSTANT(FUNC_SINH);
+ BIND_ENUM_CONSTANT(FUNC_COSH);
+ BIND_ENUM_CONSTANT(FUNC_TANH);
+ BIND_ENUM_CONSTANT(FUNC_LOG);
+ BIND_ENUM_CONSTANT(FUNC_EXP);
+ BIND_ENUM_CONSTANT(FUNC_SQRT);
+ BIND_ENUM_CONSTANT(FUNC_ABS);
+ BIND_ENUM_CONSTANT(FUNC_SIGN);
+ BIND_ENUM_CONSTANT(FUNC_FLOOR);
+ BIND_ENUM_CONSTANT(FUNC_ROUND);
+ BIND_ENUM_CONSTANT(FUNC_CEIL);
+ BIND_ENUM_CONSTANT(FUNC_FRAC);
+ BIND_ENUM_CONSTANT(FUNC_SATURATE);
+ BIND_ENUM_CONSTANT(FUNC_NEGATE);
+}
+
+VisualShaderNodeScalarFunc::VisualShaderNodeScalarFunc() {
+ func = FUNC_SIGN;
+ set_input_port_default_value(0, 0.0);
+}
+
+////////////// Vector Func
+
+String VisualShaderNodeVectorFunc::get_caption() const {
+ return "VectorFunc";
+}
+
+int VisualShaderNodeVectorFunc::get_input_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorFunc::PortType VisualShaderNodeVectorFunc::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorFunc::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeVectorFunc::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorFunc::PortType VisualShaderNodeVectorFunc::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ static const char *vec_func_id[FUNC_HSV2RGB + 1] = {
+ "normalize($)",
+ "max(min($,vec3(1.0)),vec3(0.0))",
+ "-($)",
+ "1.0/($)",
+ "",
+ "",
+ };
+
+ String code;
+
+ if (func == FUNC_RGB2HSV) {
+ code += "\t{\n";
+ code += "\t\tvec3 c = " + p_input_vars[0] + ";\n";
+ code += "\t\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
+ code += "\t\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
+ code += "\t\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
+ code += "\t\tfloat d = q.x - min(q.w, q.y);\n";
+ code += "\t\tfloat e = 1.0e-10;\n";
+ code += "\t\t" + p_output_vars[0] + "=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
+ code += "\t}\n";
+ } else if (func == FUNC_HSV2RGB) {
+ code += "\t{\n";
+ code += "\t\tvec3 c = " + p_input_vars[0] + ";\n";
+ code += "\t\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
+ code += "\t\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
+ code += "\t\t" + p_output_vars[0] + "=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
+ code += "\t}\n";
+
+ } else {
+ code += "\t" + p_output_vars[0] + "=" + String(vec_func_id[func]).replace("$", p_input_vars[0]) + ";\n";
+ }
+
+ return code;
+}
+
+void VisualShaderNodeVectorFunc::set_function(Function p_func) {
+
+ func = p_func;
+ emit_changed();
+}
+
+VisualShaderNodeVectorFunc::Function VisualShaderNodeVectorFunc::get_function() const {
+
+ return func;
+}
+
+Vector<StringName> VisualShaderNodeVectorFunc::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("function");
+ return props;
+}
+
+void VisualShaderNodeVectorFunc::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
+ ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB"), "set_function", "get_function");
+
+ BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
+ BIND_ENUM_CONSTANT(FUNC_SATURATE);
+ BIND_ENUM_CONSTANT(FUNC_NEGATE);
+ BIND_ENUM_CONSTANT(FUNC_RECIPROCAL);
+ BIND_ENUM_CONSTANT(FUNC_RGB2HSV);
+ BIND_ENUM_CONSTANT(FUNC_HSV2RGB);
+}
+
+VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() {
+ func = FUNC_NORMALIZE;
+ set_input_port_default_value(0, Vector3());
+}
+
+////////////// Dot Product
+
+String VisualShaderNodeDotProduct::get_caption() const {
+ return "DotProduct";
+}
+
+int VisualShaderNodeDotProduct::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeDotProduct::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "a" : "b";
+}
+
+int VisualShaderNodeDotProduct::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeDotProduct::get_output_port_name(int p_port) const {
+ return "dot";
+}
+
+String VisualShaderNodeDotProduct::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = dot( " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n";
+}
+
+VisualShaderNodeDotProduct::VisualShaderNodeDotProduct() {
+ set_input_port_default_value(0, Vector3());
+ set_input_port_default_value(1, Vector3());
+}
+
+////////////// Vector Len
+
+String VisualShaderNodeVectorLen::get_caption() const {
+ return "VectorLen";
+}
+
+int VisualShaderNodeVectorLen::get_input_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorLen::PortType VisualShaderNodeVectorLen::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorLen::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeVectorLen::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorLen::PortType VisualShaderNodeVectorLen::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeVectorLen::get_output_port_name(int p_port) const {
+ return "length";
+}
+
+String VisualShaderNodeVectorLen::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = length( " + p_input_vars[0] + " );\n";
+}
+
+VisualShaderNodeVectorLen::VisualShaderNodeVectorLen() {
+ set_input_port_default_value(0, Vector3());
+}
+
+////////////// Scalar Interp
+
+String VisualShaderNodeScalarInterp::get_caption() const {
+ return "ScalarInterp";
+}
+
+int VisualShaderNodeScalarInterp::get_input_port_count() const {
+ return 3;
+}
+VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "a";
+ } else if (p_port == 1) {
+ return "b";
+ } else {
+ return "c";
+ }
+}
+
+int VisualShaderNodeScalarInterp::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const {
+ return "mix";
+}
+
+String VisualShaderNodeScalarInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 0.0);
+}
+
+////////////// Vector Interp
+
+String VisualShaderNodeVectorInterp::get_caption() const {
+ return "VectorInterp";
+}
+
+int VisualShaderNodeVectorInterp::get_input_port_count() const {
+ return 3;
+}
+VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorInterp::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "a";
+ } else if (p_port == 1) {
+ return "b";
+ } else {
+ return "c";
+ }
+}
+
+int VisualShaderNodeVectorInterp::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const {
+ return "mix";
+}
+
+String VisualShaderNodeVectorInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = mix( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeVectorInterp::VisualShaderNodeVectorInterp() {
+ set_input_port_default_value(0, Vector3());
+ set_input_port_default_value(1, Vector3());
+ set_input_port_default_value(2, Vector3());
+}
+
+////////////// Vector Compose
+String VisualShaderNodeVectorCompose::get_caption() const {
+ return "VectorCompose";
+}
+
+int VisualShaderNodeVectorCompose::get_input_port_count() const {
+ return 3;
+}
+VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeVectorCompose::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "x";
+ } else if (p_port == 1) {
+ return "y";
+ } else {
+ return "z";
+ }
+}
+
+int VisualShaderNodeVectorCompose::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorCompose::get_output_port_name(int p_port) const {
+ return "vec";
+}
+
+String VisualShaderNodeVectorCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = vec3( " + p_input_vars[0] + " , " + p_input_vars[1] + " , " + p_input_vars[2] + " );\n";
+}
+
+VisualShaderNodeVectorCompose::VisualShaderNodeVectorCompose() {
+
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 0.0);
+}
+
+////////////// Transform Compose
+
+String VisualShaderNodeTransformCompose::get_caption() const {
+ return "TransformCompose";
+}
+
+int VisualShaderNodeTransformCompose::get_input_port_count() const {
+ return 4;
+}
+VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeTransformCompose::get_input_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "x";
+ } else if (p_port == 1) {
+ return "y";
+ } else if (p_port == 2) {
+ return "z";
+ } else {
+ return "origin";
+ }
+}
+
+int VisualShaderNodeTransformCompose::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+String VisualShaderNodeTransformCompose::get_output_port_name(int p_port) const {
+ return "xform";
+}
+
+String VisualShaderNodeTransformCompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = mat4( vec4(" + p_input_vars[0] + ", 0.0) , vec4(" + p_input_vars[1] + ", 0.0) , vec4(" + p_input_vars[2] + ",0.0), vec4(" + p_input_vars[3] + ",1.0) );\n";
+}
+
+VisualShaderNodeTransformCompose::VisualShaderNodeTransformCompose() {
+
+ set_input_port_default_value(0, Vector3());
+ set_input_port_default_value(1, Vector3());
+ set_input_port_default_value(2, Vector3());
+ set_input_port_default_value(3, Vector3());
+}
+
+////////////// Vector Decompose
+String VisualShaderNodeVectorDecompose::get_caption() const {
+ return "VectorDecompose";
+}
+
+int VisualShaderNodeVectorDecompose::get_input_port_count() const {
+ return 1;
+}
+VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVectorDecompose::get_input_port_name(int p_port) const {
+ return "vec";
+}
+
+int VisualShaderNodeVectorDecompose::get_output_port_count() const {
+ return 3;
+}
+VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "x";
+ } else if (p_port == 1) {
+ return "y";
+ } else {
+ return "z";
+ }
+}
+
+String VisualShaderNodeVectorDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ String code;
+ code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n";
+ code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n";
+ code += "\t" + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n";
+ return code;
+}
+
+VisualShaderNodeVectorDecompose::VisualShaderNodeVectorDecompose() {
+ set_input_port_default_value(0, Vector3());
+}
+
+////////////// Transform Decompose
+
+String VisualShaderNodeTransformDecompose::get_caption() const {
+ return "TransformDecompose";
+}
+
+int VisualShaderNodeTransformDecompose::get_input_port_count() const {
+ return 1;
+}
+VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_input_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+String VisualShaderNodeTransformDecompose::get_input_port_name(int p_port) const {
+ return "xform";
+}
+
+int VisualShaderNodeTransformDecompose::get_output_port_count() const {
+ return 4;
+}
+VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeTransformDecompose::get_output_port_name(int p_port) const {
+ if (p_port == 0) {
+ return "x";
+ } else if (p_port == 1) {
+ return "y";
+ } else if (p_port == 2) {
+ return "z";
+ } else {
+ return "origin";
+ }
+}
+
+String VisualShaderNodeTransformDecompose::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ String code;
+ code += "\t" + p_output_vars[0] + " = " + p_input_vars[0] + "[0].xyz;\n";
+ code += "\t" + p_output_vars[1] + " = " + p_input_vars[0] + "[1].xyz;\n";
+ code += "\t" + p_output_vars[2] + " = " + p_input_vars[0] + "[2].xyz;\n";
+ code += "\t" + p_output_vars[3] + " = " + p_input_vars[0] + "[3].xyz;\n";
+ return code;
+}
+
+VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() {
+ set_input_port_default_value(0, Transform());
+}
+
+////////////// Scalar Uniform
+
+String VisualShaderNodeScalarUniform::get_caption() const {
+ return "ScalarUniform";
+}
+
+int VisualShaderNodeScalarUniform::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeScalarUniform::PortType VisualShaderNodeScalarUniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarUniform::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeScalarUniform::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeScalarUniform::PortType VisualShaderNodeScalarUniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeScalarUniform::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeScalarUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform float " + get_uniform_name() + ";\n";
+}
+String VisualShaderNodeScalarUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+}
+
+VisualShaderNodeScalarUniform::VisualShaderNodeScalarUniform() {
+}
+
+////////////// Color Uniform
+
+String VisualShaderNodeColorUniform::get_caption() const {
+ return "ColorUniform";
+}
+
+int VisualShaderNodeColorUniform::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeColorUniform::get_output_port_count() const {
+ return 2;
+}
+VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const {
+ return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port
+}
+
+String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+
+ return "uniform vec4 " + get_uniform_name() + " : hint_color;\n";
+}
+
+String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
+ code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
+ return code;
+}
+
+VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() {
+}
+
+////////////// Vector Uniform
+
+String VisualShaderNodeVec3Uniform::get_caption() const {
+ return "VectorUniform";
+}
+
+int VisualShaderNodeVec3Uniform::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeVec3Uniform::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform vec3 " + get_uniform_name() + ";\n";
+}
+
+String VisualShaderNodeVec3Uniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+}
+
+VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() {
+}
+
+////////////// Transform Uniform
+
+String VisualShaderNodeTransformUniform::get_caption() const {
+ return "TransformUniform";
+}
+
+int VisualShaderNodeTransformUniform::get_input_port_count() const {
+ return 0;
+}
+VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeTransformUniform::get_output_port_count() const {
+ return 1;
+}
+VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_TRANSFORM;
+}
+String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const {
+ return ""; //no output port means the editor will be used as port
+}
+String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform mat4 " + get_uniform_name() + ";\n";
+}
+
+String VisualShaderNodeTransformUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
+}
+
+VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() {
+}
+
+////////////// Texture Uniform
+
+String VisualShaderNodeTextureUniform::get_caption() const {
+ return "TextureUniform";
+}
+
+int VisualShaderNodeTextureUniform::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "uv" : "lod";
+}
+
+int VisualShaderNodeTextureUniform::get_output_port_count() const {
+ return 2;
+}
+VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
+ return p_port == 0 ? "rgb" : "alpha";
+}
+
+String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = "uniform sampler2D " + get_uniform_name();
+
+ switch (texture_type) {
+ case TYPE_DATA:
+ if (color_default == COLOR_DEFAULT_BLACK)
+ code += " : hint_black;\n";
+ else
+ code += ";\n";
+ break;
+ case TYPE_COLOR:
+ if (color_default == COLOR_DEFAULT_BLACK)
+ code += " : hint_black_albedo;\n";
+ else
+ code += " : hint_albedo;\n";
+ break;
+ case TYPE_NORMALMAP: code += " : hint_normal;\n"; break;
+ case TYPE_ANISO: code += " : hint_aniso;\n"; break;
+ }
+
+ return code;
+}
+
+String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+
+ String id = get_uniform_name();
+ String code = "\t{\n";
+ if (p_input_vars[0] == String()) { //none bound, do nothing
+
+ code += "\t\tvec4 n_tex_read = vec4(0.0);\n";
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\t\tvec4 n_tex_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n";
+ } else {
+ code += "\t\tvec4 n_tex_read = textureLod( " + id + " , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n";
+ code += "\t\t" + p_output_vars[1] + " = n_tex_read.a;\n";
+ code += "\t}\n";
+ return code;
+}
+
+void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_type) {
+
+ texture_type = p_type;
+ emit_changed();
+}
+
+VisualShaderNodeTextureUniform::TextureType VisualShaderNodeTextureUniform::get_texture_type() const {
+ return texture_type;
+}
+
+void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_default) {
+ color_default = p_default;
+ emit_changed();
+}
+VisualShaderNodeTextureUniform::ColorDefault VisualShaderNodeTextureUniform::get_color_default() const {
+ return color_default;
+}
+
+Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() const {
+ Vector<StringName> props;
+ props.push_back("texture_type");
+ props.push_back("color_default");
+ return props;
+}
+
+void VisualShaderNodeTextureUniform::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureUniform::set_texture_type);
+ ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureUniform::get_texture_type);
+
+ ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureUniform::set_color_default);
+ ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureUniform::get_color_default);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap,Aniso"), "set_texture_type", "get_texture_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White Default,Black Default"), "set_color_default", "get_color_default");
+
+ BIND_ENUM_CONSTANT(TYPE_DATA);
+ BIND_ENUM_CONSTANT(TYPE_COLOR);
+ BIND_ENUM_CONSTANT(TYPE_NORMALMAP);
+ BIND_ENUM_CONSTANT(TYPE_ANISO);
+
+ BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE);
+ BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK);
+}
+
+VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
+ texture_type = TYPE_DATA;
+ color_default = COLOR_DEFAULT_WHITE;
+}
+
+////////////// CubeMap Uniform
+
+String VisualShaderNodeCubeMapUniform::get_caption() const {
+ return "CubeMapUniform";
+}
+
+int VisualShaderNodeCubeMapUniform::get_input_port_count() const {
+ return 2;
+}
+VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_input_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeCubeMapUniform::get_input_port_name(int p_port) const {
+ return p_port == 0 ? "normal" : "lod";
+}
+
+int VisualShaderNodeCubeMapUniform::get_output_port_count() const {
+ return 2;
+}
+VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_output_port_type(int p_port) const {
+ return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+}
+String VisualShaderNodeCubeMapUniform::get_output_port_name(int p_port) const {
+ return p_port == 0 ? "rgb" : "alpha";
+}
+
+String VisualShaderNodeCubeMapUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const {
+ return String();
+}
+
+VisualShaderNodeCubeMapUniform::VisualShaderNodeCubeMapUniform() {
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
new file mode 100644
index 0000000000..3057f7239a
--- /dev/null
+++ b/scene/resources/visual_shader_nodes.h
@@ -0,0 +1,891 @@
+/*************************************************************************/
+/* visual_shader_nodes.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 VISUAL_SHADER_NODES_H
+#define VISUAL_SHADER_NODES_H
+
+#include "scene/resources/visual_shader.h"
+
+/// CONSTANTS ///
+
+class VisualShaderNodeScalarConstant : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarConstant, VisualShaderNode)
+ float constant;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_constant(float p_value);
+ float get_constant() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeScalarConstant();
+};
+
+class VisualShaderNodeColorConstant : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode)
+ Color constant;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_constant(Color p_value);
+ Color get_constant() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeColorConstant();
+};
+
+class VisualShaderNodeVec3Constant : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode)
+ Vector3 constant;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_constant(Vector3 p_value);
+ Vector3 get_constant() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeVec3Constant();
+};
+
+class VisualShaderNodeTransformConstant : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode)
+ Transform constant;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_constant(Transform p_value);
+ Transform get_constant() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeTransformConstant();
+};
+
+//////////////////////////////////
+
+class VisualShaderNodeTexture : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTexture, VisualShaderNode)
+ Ref<Texture> texture;
+
+public:
+ enum Source {
+ SOURCE_TEXTURE,
+ SOURCE_SCREEN,
+ SOURCE_2D_TEXTURE,
+ SOURCE_2D_NORMAL
+ };
+
+ enum TextureType {
+ TYPE_DATA,
+ TYPE_COLOR,
+ TYPE_NORMALMAP
+ };
+
+private:
+ Source source;
+ TextureType texture_type;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_source(Source p_source);
+ Source get_source() const;
+
+ void set_texture(Ref<Texture> p_value);
+ Ref<Texture> get_texture() const;
+
+ void set_texture_type(TextureType p_type);
+ TextureType get_texture_type() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const;
+
+ VisualShaderNodeTexture();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeTexture::TextureType)
+VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source)
+
+//////////////////////////////////
+
+class VisualShaderNodeCubeMap : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeCubeMap, VisualShaderNode)
+ Ref<CubeMap> cube_map;
+
+public:
+ enum TextureType {
+ TYPE_DATA,
+ TYPE_COLOR,
+ TYPE_NORMALMAP
+ };
+
+private:
+ TextureType texture_type;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_cube_map(Ref<CubeMap> p_value);
+ Ref<CubeMap> get_cube_map() const;
+
+ void set_texture_type(TextureType p_type);
+ TextureType get_texture_type() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeCubeMap();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeCubeMap::TextureType)
+///////////////////////////////////////
+
+class VisualShaderNodeScalarOp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarOp, VisualShaderNode)
+
+public:
+ enum Operator {
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_POW,
+ OP_MAX,
+ OP_MIN,
+ OP_ATAN2
+ };
+
+protected:
+ Operator op;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_operator(Operator p_op);
+ Operator get_operator() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeScalarOp();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeScalarOp::Operator)
+
+class VisualShaderNodeVectorOp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorOp, VisualShaderNode)
+
+public:
+ enum Operator {
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_POW,
+ OP_MAX,
+ OP_MIN,
+ OP_CROSS
+
+ };
+
+protected:
+ Operator op;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_operator(Operator p_op);
+ Operator get_operator() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeVectorOp();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeVectorOp::Operator)
+
+class VisualShaderNodeColorOp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeColorOp, VisualShaderNode)
+
+public:
+ enum Operator {
+ OP_SCREEN,
+ OP_DIFFERENCE,
+ OP_DARKEN,
+ OP_LIGHTEN,
+ OP_OVERLAY,
+ OP_DODGE,
+ OP_BURN,
+ OP_SOFT_LIGHT,
+ OP_HARD_LIGHT,
+ };
+
+protected:
+ Operator op;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_operator(Operator p_op);
+ Operator get_operator() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeColorOp();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeColorOp::Operator)
+
+class VisualShaderNodeTransformMult : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTransformMult, VisualShaderNode)
+
+public:
+ enum Operator {
+ OP_AxB,
+ OP_BxA,
+ };
+
+protected:
+ Operator op;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_operator(Operator p_op);
+ Operator get_operator() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeTransformMult();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeTransformMult::Operator)
+
+class VisualShaderNodeTransformVecMult : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTransformVecMult, VisualShaderNode)
+
+public:
+ enum Operator {
+ OP_AxB,
+ OP_BxA,
+ OP_3x3_AxB,
+ OP_3x3_BxA,
+ };
+
+protected:
+ Operator op;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_operator(Operator p_op);
+ Operator get_operator() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeTransformVecMult();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeTransformVecMult::Operator)
+
+///////////////////////////////////////
+
+class VisualShaderNodeScalarFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarFunc, VisualShaderNode)
+
+public:
+ enum Function {
+ FUNC_SIN,
+ FUNC_COS,
+ FUNC_TAN,
+ FUNC_ASIN,
+ FUNC_ACOS,
+ FUNC_ATAN,
+ FUNC_SINH,
+ FUNC_COSH,
+ FUNC_TANH,
+ FUNC_LOG,
+ FUNC_EXP,
+ FUNC_SQRT,
+ FUNC_ABS,
+ FUNC_SIGN,
+ FUNC_FLOOR,
+ FUNC_ROUND,
+ FUNC_CEIL,
+ FUNC_FRAC,
+ FUNC_SATURATE,
+ FUNC_NEGATE,
+ };
+
+protected:
+ Function func;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_function(Function p_func);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeScalarFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeScalarFunc::Function)
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorFunc : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNode)
+
+public:
+ enum Function {
+ FUNC_NORMALIZE,
+ FUNC_SATURATE,
+ FUNC_NEGATE,
+ FUNC_RECIPROCAL,
+ FUNC_RGB2HSV,
+ FUNC_HSV2RGB,
+ };
+
+protected:
+ Function func;
+
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ void set_function(Function p_func);
+ Function get_function() const;
+
+ virtual Vector<StringName> get_editable_properties() const;
+
+ VisualShaderNodeVectorFunc();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeVectorFunc::Function)
+
+///////////////////////////////////////
+
+class VisualShaderNodeDotProduct : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeDotProduct, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeDotProduct();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorLen : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorLen();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeScalarInterp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeScalarInterp();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorInterp : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorInterp();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorCompose : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorCompose();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeTransformCompose : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTransformCompose, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeTransformCompose();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeVectorDecompose : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVectorDecompose();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeTransformDecompose : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeTransformDecompose, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeTransformDecompose();
+};
+
+///////////////////////////////////////
+
+class VisualShaderNodeScalarUniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeScalarUniform, VisualShaderNodeUniform)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeScalarUniform();
+};
+
+class VisualShaderNodeColorUniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeColorUniform();
+};
+
+class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeVec3Uniform();
+};
+
+class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeTransformUniform();
+};
+
+//////////////////////////////////
+
+class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform {
+ GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform)
+public:
+ enum TextureType {
+ TYPE_DATA,
+ TYPE_COLOR,
+ TYPE_NORMALMAP,
+ TYPE_ANISO,
+ };
+
+ enum ColorDefault {
+ COLOR_DEFAULT_WHITE,
+ COLOR_DEFAULT_BLACK
+ };
+
+private:
+ TextureType texture_type;
+ ColorDefault color_default;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ Vector<StringName> get_editable_properties() const;
+
+ void set_texture_type(TextureType p_type);
+ TextureType get_texture_type() const;
+
+ void set_color_default(ColorDefault p_default);
+ ColorDefault get_color_default() const;
+
+ VisualShaderNodeTextureUniform();
+};
+
+VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault)
+
+//////////////////////////////////
+
+class VisualShaderNodeCubeMapUniform : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode)
+
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+ VisualShaderNodeCubeMapUniform();
+};
+
+#endif // VISUAL_SHADER_NODES_H
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index bf765385d0..e468b3dab4 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -102,6 +102,8 @@ SceneStringNames::SceneStringNames() {
_update_scroll = StaticCString::create("_update_scroll");
_update_xform = StaticCString::create("_update_xform");
+ _clips_input = StaticCString::create("_clips_input");
+
_proxgroup_add = StaticCString::create("_proxgroup_add");
_proxgroup_remove = StaticCString::create("_proxgroup_remove");
@@ -199,4 +201,6 @@ SceneStringNames::SceneStringNames() {
}
_mesh_changed = StaticCString::create("_mesh_changed");
+
+ parameters_base_path = "parameters/";
}
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index b88cf7d8d7..dbbcf79b9f 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -127,6 +127,8 @@ public:
StringName _update_scroll;
StringName _update_xform;
+ StringName _clips_input;
+
StringName _proxgroup_add;
StringName _proxgroup_remove;
@@ -201,6 +203,8 @@ public:
StringName output;
+ StringName parameters_base_path;
+
enum {
MAX_MATERIALS = 32
};