From f28029c189709b229f39474a33af2a8d934e7a04 Mon Sep 17 00:00:00 2001 From: rowan Date: Mon, 9 Jun 2025 23:12:19 -0400 Subject: [PATCH] idr --- godot/addons/iterator/bounded_range.gd | 28 + godot/addons/iterator/fused.gd | 22 + godot/addons/iterator/iterator.gd | 9 +- godot/addons/iterator/range.gd | 33 +- godot/addons/monads/option.gd | 21 +- .../assets/PhantomCameraBtnPrimaryDefault.png | Bin 0 -> 10296 bytes .../PhantomCameraBtnPrimaryDefault.png.import | 34 + .../assets/PhantomCameraBtnPrimaryHover.png | Bin 0 -> 9931 bytes .../PhantomCameraBtnPrimaryHover.png.import | 34 + .../phantom_camera/examples/credits.txt | 7 + .../2D-4.3/2d_example_scene.tscn | 249 ++ .../2d_follow_framed_example_scene.tscn | 251 ++ .../2D-4.3/2d_follow_group_example_scene.tscn | 261 ++ .../2D-4.3/2d_follow_path_example_scene.tscn | 269 ++ .../2D-4.3/2d_limit_example_scene.tscn | 319 +++ .../2D-4.3/2d_noise_example_scene.tscn | 289 +++ .../2D-4.3/2d_tweening_example_scene.tscn | 402 +++ .../example_scenes/2D/2d_example_scene.tscn | 245 ++ .../2D/2d_follow_framed_example_scene.tscn | 245 ++ .../2D/2d_follow_group_example_scene.tscn | 255 ++ .../2D/2d_follow_path_example_scene.tscn | 263 ++ .../2D/2d_limit_example_scene.tscn | 324 +++ .../2D/2d_tweening_example_scene.tscn | 397 +++ .../2D/sub_scenes/playable_character_2d.tscn | 120 + .../3D-4.4/3d_example_scene.tscn | 413 +++ .../3d_follow_framed_example_scene.tscn | 158 ++ .../3D-4.4/3d_follow_glued_example_scene.tscn | 211 ++ .../3D-4.4/3d_follow_group_example_scene.tscn | 180 ++ .../3D-4.4/3d_follow_path_example_scene.tscn | 245 ++ .../3d_follow_simple_example_scene.tscn | 164 ++ ...third_person_attribtues_example_scene.tscn | 222 ++ .../3d_follow_third_person_example_scene.tscn | 190 ++ .../3D-4.4/3d_look_at_example_scene.tscn | 200 ++ .../3D-4.4/3d_noise_example_scene.tscn | 195 ++ .../3D-4.4/3d_tweening_example_scene.tscn | 293 +++ .../sub_scenes/playable_character_3d.tscn | 31 + .../playable_character_third_person_3d.tscn | 43 + .../example_scenes/3D/3d_example_scene.tscn | 412 +++ .../3D/3d_follow_framed_example_scene.tscn | 156 ++ .../3D/3d_follow_glued_example_scene.tscn | 208 ++ .../3D/3d_follow_group_example_scene.tscn | 180 ++ .../3D/3d_follow_path_example_scene.tscn | 244 ++ .../3D/3d_follow_simple_example_scene.tscn | 163 ++ ...third_person_attribtues_example_scene.tscn | 219 ++ .../3d_follow_third_person_example_scene.tscn | 188 ++ .../3D/3d_look_at_example_scene.tscn | 198 ++ .../3D/3d_noise_example_scene.tscn | 210 ++ .../3D/3d_tweening_example_scene.tscn | 291 +++ .../3D/sub_scenes/playable_character_3d.tscn | 30 + .../playable_character_third_person_3d.tscn | 43 + .../examples/models/3d_cube_dark.tscn | 15 + .../resources/tween/fixed_camera_tween.tres | 9 + .../inventory_phantom_camera_2d_tween.tres | 9 + .../item_focus_phantom_camera_2d_tween.tres | 9 + .../tween/player_phantom_camera_2d_tween.tres | 9 + .../tween/player_phantom_camera_3d_tween.tres | 9 + .../scripts/2D/2d_room_limit_tween.gd | 36 + .../scripts/2D/2d_room_limit_tween_4.3.gd | 36 + .../examples/scripts/2D/2d_trigger_area.gd | 16 + .../scripts/2D/player_character_body_2d.gd | 189 ++ .../2D/player_character_body_2d_4.3.gd | 179 ++ .../examples/scripts/3D/3d_trigger_area.gd | 26 + .../phantom_camera/examples/scripts/3D/npc.gd | 71 + .../examples/scripts/3D/path_follow.gd | 17 + .../examples/scripts/3D/player_controller.gd | 103 + .../scripts/3D/player_controller_4.4.gd | 84 + .../3D/player_controller_first_person.gd | 54 + .../3D/player_controller_first_person_4.4.gd | 54 + .../3D/player_controller_third_person.gd | 87 + .../3D/player_controller_third_person_4.4.gd | 86 + .../textures/2D/inventory_container.png | Bin 0 -> 68739 bytes .../2D/inventory_container.png.import | 34 + .../textures/2D/level_spritesheet.png | Bin 0 -> 10314 bytes .../textures/2D/level_spritesheet.png.import | 34 + .../textures/2D/phantom_camera_2d_sprite.png | Bin 0 -> 1584 bytes .../2D/phantom_camera_2d_sprite.png.import | 34 + .../examples/textures/2D/player_sprite.svg | 4 + .../textures/2D/player_sprite.svg.import | 37 + .../examples/textures/2D/sign_prompt.png | Bin 0 -> 175934 bytes .../textures/2D/sign_prompt.png.import | 34 + .../textures/3D/checker_pattern_dark.png | Bin 0 -> 2861 bytes .../3D/checker_pattern_dark.png.import | 35 + .../examples/textures/3D/target.png | Bin 0 -> 96068 bytes .../examples/textures/3D/target.png.import | 35 + .../examples/ui/ui_inventory.tscn | 37 + .../phantom_camera/examples/ui/ui_sign.tscn | 83 + .../phantom_camera/fonts/Nunito-Black.ttf | Bin 0 -> 131568 bytes .../fonts/Nunito-Black.ttf.import | 35 + .../phantom_camera/fonts/Nunito-Regular.ttf | Bin 0 -> 131736 bytes .../fonts/Nunito-Regular.ttf.import | 35 + .../icons/misc/PriorityOverride.svg | 14 + .../icons/misc/PriorityOverride.svg.import | 37 + .../icons/phantom_camera_2d.svg | 1 + .../icons/phantom_camera_2d.svg.import | 37 + .../icons/phantom_camera_3d.svg | 1 + .../icons/phantom_camera_3d.svg.import | 37 + .../phantom_camera_camera_3d_resource.svg | 3 + ...antom_camera_camera_3d_resource.svg.import | 37 + .../icons/phantom_camera_gizmo.svg | 1 + .../icons/phantom_camera_gizmo.svg.import | 38 + .../icons/phantom_camera_glow_logo.png | Bin 0 -> 25499 bytes .../icons/phantom_camera_glow_logo.png.import | 34 + .../icons/phantom_camera_host.svg | 1 + .../icons/phantom_camera_host.svg.import | 38 + .../icons/phantom_camera_logo.png | Bin 0 -> 70905 bytes .../icons/phantom_camera_logo.png.import | 34 + .../icons/phantom_camera_noise_emitter_2d.svg | 4 + ...phantom_camera_noise_emitter_2d.svg.import | 37 + .../icons/phantom_camera_noise_emitter_3d.svg | 4 + ...phantom_camera_noise_emitter_3d.svg.import | 38 + .../phantom_camera_noise_emitter_gizmo.svg | 4 + ...ntom_camera_noise_emitter_gizmo.svg.import | 38 + .../icons/phantom_camera_noise_resource.svg | 5 + .../phantom_camera_noise_resource.svg.import | 37 + .../icons/phantom_camera_tween.svg | 1 + .../icons/phantom_camera_tween.svg.import | 38 + .../phantom_camera_updater_panel_icon.svg | 3 + ...antom_camera_updater_panel_icon.svg.import | 37 + .../icons/viewfinder/Camera2DIcon.svg | 3 + .../icons/viewfinder/Camera2DIcon.svg.import | 37 + .../icons/viewfinder/Camera3DIcon.svg | 3 + .../icons/viewfinder/Camera3DIcon.svg.import | 37 + .../icons/viewfinder/SceneTypesIcon.svg | 4 + .../viewfinder/SceneTypesIcon.svg.import | 37 + .../icons/viewfinder/Select.svg | 3 + .../icons/viewfinder/Select.svg.import | 37 + godot/addons/phantom_camera/icons/warning.svg | 4 + .../phantom_camera/icons/warning.svg.import | 37 + .../phantom_camera_inspector_plugin.gd | 46 + godot/addons/phantom_camera/panel/editor.tscn | 23 + .../panel/updater/download_update_panel.tscn | 253 ++ .../panel/updater/update_button.tscn | 101 + .../panel/viewfinder/deadzone_style_box.tres | 14 + .../panel/viewfinder/host_list/host_list.tscn | 87 + .../viewfinder/host_list/host_list_item.tscn | 68 + .../host_list/host_list_item_group.tres | 3 + .../panel/viewfinder/viewfinder_panel.tscn | 563 +++++ godot/addons/phantom_camera/plugin.cfg | 7 + godot/addons/phantom_camera/plugin.gd | 181 ++ .../scripts/gizmos/phantom_camera_3d_gizmo.gd | 84 + .../gizmos/phantom_camera_3d_gizmo_plugin.gd | 37 + ...om_camera_noise_emitter_gizmo_plugin_3d.gd | 29 + .../scripts/managers/PhantomCameraManager.cs | 36 + .../managers/phantom_camera_manager.gd | 149 ++ .../phantom_camera/scripts/panel/editor.gd | 23 + .../panel/updater/download_update_panel.gd | 162 ++ .../scripts/panel/updater/update_button.gd | 177 ++ .../panel/updater/updater_constants.gd | 8 + .../scripts/panel/viewfinder/host_list.gd | 112 + .../panel/viewfinder/host_list_item.gd | 58 + .../scripts/panel/viewfinder/viewfinder.gd | 605 +++++ .../scripts/phantom_camera/PhantomCamera.cs | 253 ++ .../scripts/phantom_camera/PhantomCamera2D.cs | 315 +++ .../scripts/phantom_camera/PhantomCamera3D.cs | 475 ++++ .../PhantomCameraNoiseEmitter2D.cs | 83 + .../PhantomCameraNoiseEmitter3D.cs | 83 + .../phantom_camera/phantom_camera_2d.gd | 1614 ++++++++++++ .../phantom_camera/phantom_camera_3d.gd | 2229 +++++++++++++++++ .../phantom_camera_constants.gd | 29 + .../phantom_camera_noise_emitter_2d.gd | 264 ++ .../phantom_camera_noise_emitter_3d.gd | 265 ++ .../phantom_camera_host/PhantomCameraHost.cs | 122 + .../phantom_camera_host.gd | 1437 +++++++++++ .../scripts/resources/Camera3DResource.cs | 117 + .../scripts/resources/PhantomCameraNoise2D.cs | 92 + .../scripts/resources/PhantomCameraNoise3D.cs | 119 + .../scripts/resources/PhantomCameraTween.cs | 64 + .../scripts/resources/camera_3d_resource.gd | 110 + .../resources/phantom_camera_noise_2d.gd | 228 ++ .../resources/phantom_camera_noise_3d.gd | 301 +++ .../scripts/resources/tween_resource.gd | 41 + .../phantom_camera/themes/button_focus.tres | 17 + .../phantom_camera/themes/button_hover.tres | 13 + .../phantom_camera/themes/button_normal.tres | 17 + godot/addons/phantom_camera/themes/theme.tres | 102 + godot/addons/range/integer.gd | 20 + godot/project.godot | 18 + godot/resources/items/key.tres | 12 + godot/resources/player_inventory.tres | 10 + godot/scenes/inventory.tscn | 57 + godot/scenes/inventory_item.tscn | 15 + godot/scenes/level.tscn | 54 +- godot/src/h_item_list.gd | 75 + godot/src/input_listener.gd | 13 + godot/src/inventory.gd | 17 + godot/src/inventory_ui.gd | 9 + godot/src/item.gd | 12 + godot/src/item_ui.gd | 8 + godot/src/player.gd | 1 + godot/src/ring_buffer.gd | 69 + 190 files changed, 23032 insertions(+), 34 deletions(-) create mode 100644 godot/addons/iterator/bounded_range.gd create mode 100644 godot/addons/iterator/fused.gd create mode 100644 godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png create mode 100644 godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png.import create mode 100644 godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryHover.png create mode 100644 godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryHover.png.import create mode 100644 godot/addons/phantom_camera/examples/credits.txt create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_follow_framed_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_follow_group_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_follow_path_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_limit_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_noise_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D-4.3/2d_tweening_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/2d_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/2d_follow_framed_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/2d_follow_group_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/2d_follow_path_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/2d_limit_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/2d_tweening_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/2D/sub_scenes/playable_character_2d.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_framed_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_glued_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_group_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_path_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_simple_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_third_person_attribtues_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_follow_third_person_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_look_at_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_noise_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/3d_tweening_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/sub_scenes/playable_character_3d.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D-4.4/sub_scenes/playable_character_third_person_3d.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_framed_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_glued_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_group_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_path_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_simple_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_third_person_attribtues_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_follow_third_person_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_look_at_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_noise_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/3d_tweening_example_scene.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/sub_scenes/playable_character_3d.tscn create mode 100644 godot/addons/phantom_camera/examples/example_scenes/3D/sub_scenes/playable_character_third_person_3d.tscn create mode 100644 godot/addons/phantom_camera/examples/models/3d_cube_dark.tscn create mode 100644 godot/addons/phantom_camera/examples/resources/tween/fixed_camera_tween.tres create mode 100644 godot/addons/phantom_camera/examples/resources/tween/inventory_phantom_camera_2d_tween.tres create mode 100644 godot/addons/phantom_camera/examples/resources/tween/item_focus_phantom_camera_2d_tween.tres create mode 100644 godot/addons/phantom_camera/examples/resources/tween/player_phantom_camera_2d_tween.tres create mode 100644 godot/addons/phantom_camera/examples/resources/tween/player_phantom_camera_3d_tween.tres create mode 100644 godot/addons/phantom_camera/examples/scripts/2D/2d_room_limit_tween.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/2D/2d_room_limit_tween_4.3.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/2D/2d_trigger_area.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d_4.3.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/3d_trigger_area.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/npc.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/path_follow.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/player_controller.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/player_controller_4.4.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person_4.4.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person.gd create mode 100644 godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person_4.4.gd create mode 100644 godot/addons/phantom_camera/examples/textures/2D/inventory_container.png create mode 100644 godot/addons/phantom_camera/examples/textures/2D/inventory_container.png.import create mode 100644 godot/addons/phantom_camera/examples/textures/2D/level_spritesheet.png create mode 100644 godot/addons/phantom_camera/examples/textures/2D/level_spritesheet.png.import create mode 100644 godot/addons/phantom_camera/examples/textures/2D/phantom_camera_2d_sprite.png create mode 100644 godot/addons/phantom_camera/examples/textures/2D/phantom_camera_2d_sprite.png.import create mode 100644 godot/addons/phantom_camera/examples/textures/2D/player_sprite.svg create mode 100644 godot/addons/phantom_camera/examples/textures/2D/player_sprite.svg.import create mode 100644 godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png create mode 100644 godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png.import create mode 100644 godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png create mode 100644 godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png.import create mode 100644 godot/addons/phantom_camera/examples/textures/3D/target.png create mode 100644 godot/addons/phantom_camera/examples/textures/3D/target.png.import create mode 100644 godot/addons/phantom_camera/examples/ui/ui_inventory.tscn create mode 100644 godot/addons/phantom_camera/examples/ui/ui_sign.tscn create mode 100644 godot/addons/phantom_camera/fonts/Nunito-Black.ttf create mode 100644 godot/addons/phantom_camera/fonts/Nunito-Black.ttf.import create mode 100644 godot/addons/phantom_camera/fonts/Nunito-Regular.ttf create mode 100644 godot/addons/phantom_camera/fonts/Nunito-Regular.ttf.import create mode 100644 godot/addons/phantom_camera/icons/misc/PriorityOverride.svg create mode 100644 godot/addons/phantom_camera/icons/misc/PriorityOverride.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_2d.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_2d.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_3d.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_3d.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_glow_logo.png create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_glow_logo.png.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_host.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_host.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_logo.png create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_logo.png.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_tween.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_tween.svg.import create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg create mode 100644 godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg.import create mode 100644 godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg create mode 100644 godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg.import create mode 100644 godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg create mode 100644 godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg.import create mode 100644 godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg create mode 100644 godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg.import create mode 100644 godot/addons/phantom_camera/icons/viewfinder/Select.svg create mode 100644 godot/addons/phantom_camera/icons/viewfinder/Select.svg.import create mode 100644 godot/addons/phantom_camera/icons/warning.svg create mode 100644 godot/addons/phantom_camera/icons/warning.svg.import create mode 100644 godot/addons/phantom_camera/inspector/phantom_camera_inspector_plugin.gd create mode 100644 godot/addons/phantom_camera/panel/editor.tscn create mode 100644 godot/addons/phantom_camera/panel/updater/download_update_panel.tscn create mode 100644 godot/addons/phantom_camera/panel/updater/update_button.tscn create mode 100644 godot/addons/phantom_camera/panel/viewfinder/deadzone_style_box.tres create mode 100644 godot/addons/phantom_camera/panel/viewfinder/host_list/host_list.tscn create mode 100644 godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item.tscn create mode 100644 godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres create mode 100644 godot/addons/phantom_camera/panel/viewfinder/viewfinder_panel.tscn create mode 100644 godot/addons/phantom_camera/plugin.cfg create mode 100644 godot/addons/phantom_camera/plugin.gd create mode 100644 godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo.gd create mode 100644 godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo_plugin.gd create mode 100644 godot/addons/phantom_camera/scripts/gizmos/phantom_camera_noise_emitter_gizmo_plugin_3d.gd create mode 100644 godot/addons/phantom_camera/scripts/managers/PhantomCameraManager.cs create mode 100644 godot/addons/phantom_camera/scripts/managers/phantom_camera_manager.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/editor.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/updater/download_update_panel.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/updater/update_button.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/updater/updater_constants.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/viewfinder/host_list.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/viewfinder/host_list_item.gd create mode 100644 godot/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera.cs create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera2D.cs create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera3D.cs create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter2D.cs create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter3D.cs create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_2d.gd create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_3d.gd create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera_host/PhantomCameraHost.cs create mode 100644 godot/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd create mode 100644 godot/addons/phantom_camera/scripts/resources/Camera3DResource.cs create mode 100644 godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise2D.cs create mode 100644 godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise3D.cs create mode 100644 godot/addons/phantom_camera/scripts/resources/PhantomCameraTween.cs create mode 100644 godot/addons/phantom_camera/scripts/resources/camera_3d_resource.gd create mode 100644 godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_2d.gd create mode 100644 godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_3d.gd create mode 100644 godot/addons/phantom_camera/scripts/resources/tween_resource.gd create mode 100644 godot/addons/phantom_camera/themes/button_focus.tres create mode 100644 godot/addons/phantom_camera/themes/button_hover.tres create mode 100644 godot/addons/phantom_camera/themes/button_normal.tres create mode 100644 godot/addons/phantom_camera/themes/theme.tres create mode 100644 godot/addons/range/integer.gd create mode 100644 godot/resources/items/key.tres create mode 100644 godot/resources/player_inventory.tres create mode 100644 godot/scenes/inventory.tscn create mode 100644 godot/scenes/inventory_item.tscn create mode 100644 godot/src/h_item_list.gd create mode 100644 godot/src/input_listener.gd create mode 100644 godot/src/inventory.gd create mode 100644 godot/src/inventory_ui.gd create mode 100644 godot/src/item.gd create mode 100644 godot/src/item_ui.gd create mode 100644 godot/src/ring_buffer.gd diff --git a/godot/addons/iterator/bounded_range.gd b/godot/addons/iterator/bounded_range.gd new file mode 100644 index 0000000..e5796b0 --- /dev/null +++ b/godot/addons/iterator/bounded_range.gd @@ -0,0 +1,28 @@ +class_name BoundedRangeIterator extends Iterator + +var range: IntRange +var bounds: IntRange +var step: int +var limit: int +var index: int + +func _init(range: IntRange, bounds: IntRange, step: int = 1, limit: int = 1, start_index: int = range.min) -> void: + self.range = range + self.bounds = bounds + self.step = step + self.limit = limit + self.index = start_index + +func clone() -> BoundedRangeIterator: + return BoundedRangeIterator.new(range, bounds, step, limit, index) + +func next() -> Option: + if bounds.contains(index): + var current_value = Option.some(index) + index += step + return current_value + elif limit > 0: + limit -= 1 + index = bounds.wrap(index) + return Option.some(index) + else: return Option.none diff --git a/godot/addons/iterator/fused.gd b/godot/addons/iterator/fused.gd new file mode 100644 index 0000000..a34adf1 --- /dev/null +++ b/godot/addons/iterator/fused.gd @@ -0,0 +1,22 @@ +class_name FusedIterator extends Iterator + +var _iters: Array[Iterator] +var _index: int = 0 + +func _init(iters: Array[Iterator]) -> void: + _iters = iters + +static func from(iterator: Variant) -> FusedIterator: + var arr: Array[Iterator] = [] + for iter in iterator: + arr.append(iter) + return FusedIterator.new(arr) + +func next() -> Option: + if _index >= len(_iters): return Option.none + + match _iters[_index].next(): + var value when value.is_some(): return value + _: + _index += 1 + return next() diff --git a/godot/addons/iterator/iterator.gd b/godot/addons/iterator/iterator.gd index 4c25ed7..cbe0947 100644 --- a/godot/addons/iterator/iterator.gd +++ b/godot/addons/iterator/iterator.gd @@ -1,11 +1,18 @@ class_name Iterator extends RefCounted func clone() -> Iterator: - return Iterator.new() + assert(false, "can't clone a abstract base class") + return null func next() -> Option: return Option.none +func collect() -> Array: + var result = [] + for item in self: + result.append(item) + return result + func into_peekable() -> PeekableIter: return PeekableIter.new(self) diff --git a/godot/addons/iterator/range.gd b/godot/addons/iterator/range.gd index 4f8a032..424cbc5 100644 --- a/godot/addons/iterator/range.gd +++ b/godot/addons/iterator/range.gd @@ -1,19 +1,30 @@ class_name RangeIterator extends Iterator -var _index: int -var _to: int -var _step: int +var index: int +var range: IntRange +var step: int +var descending: bool -func _init(from: int, to: int, step: int = 1) -> void: - _index = from - 1 - _to = to - _step = step +func _init(range: IntRange, start_index: int = range.min, step: int = 1) -> void: + assert(step != 0, "step cannot be zero") + + self.range = range + self.index = start_index + self.step = step + self.descending = step < 0 + +func from_values(from: int, to: int, start_index: int = range.min, step: int = 1) -> RangeIterator: + return RangeIterator.new(IntRange.new(from, to), start_index, step) + +func length() -> int: + return range.length() func clone() -> RangeIterator: - return RangeIterator.new(_index, _to, _step) + return RangeIterator.new(range, index) func next() -> Option: - if _index < _to: - _index += 1 - return Option.some(_index) + if range.contains(index): + var current_value = Option.some(index) + index += step + return current_value else: return Option.none diff --git a/godot/addons/monads/option.gd b/godot/addons/monads/option.gd index cb34c90..03acb5b 100644 --- a/godot/addons/monads/option.gd +++ b/godot/addons/monads/option.gd @@ -8,19 +8,13 @@ static func some(value: Variant) -> Option: static var none: Option.None = None.new() static func collect_some(options: Array[Option]) -> Option: - match options: - []: return Option.none - [var x]: return x - _: - var result = [] - - for option in options: - if option.is_some(): - result.push_back(option.unwrap()) - else: - return Option.none - - return Option.some(result) + var result = [] + for option in options: + if option.is_some(): + result.push_back(option.unwrap()) + else: + return Option.none + return Option.some(result) class Some extends Option: var value: Variant @@ -84,4 +78,5 @@ class None extends Option: return fn.call() func unwrap() -> Variant: + assert(false, "Called unwrap() on a None value") return null diff --git a/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png b/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png new file mode 100644 index 0000000000000000000000000000000000000000..30827891816579e19fbc47b913ae2ff2b5937615 GIT binary patch literal 10296 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 KMNUMnLSTYWH#*1w literal 0 HcmV?d00001 diff --git a/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png.import b/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png.import new file mode 100644 index 0000000..ad3a214 --- /dev/null +++ b/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://censw3w53gldn" +path="res://.godot/imported/PhantomCameraBtnPrimaryDefault.png-fcf3696b583a82b1078609a5bfd648f5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png" +dest_files=["res://.godot/imported/PhantomCameraBtnPrimaryDefault.png-fcf3696b583a82b1078609a5bfd648f5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryHover.png b/godot/addons/phantom_camera/assets/PhantomCameraBtnPrimaryHover.png new file mode 100644 index 0000000000000000000000000000000000000000..1e0c31abaa0be755734661b39c89ce65fce62f9b GIT binary patch literal 9931 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 void: + if body == player.get_parent(): + pcam.set_follow_target(player) + pcam.set_priority(20) + + +func _on_body_exited(body: Node2D, pcam: PhantomCamera2D) -> void: + if body == player.get_parent(): + pcam.set_priority(0) + pcam.set_follow_target(null) diff --git a/godot/addons/phantom_camera/examples/scripts/2D/2d_room_limit_tween_4.3.gd b/godot/addons/phantom_camera/examples/scripts/2D/2d_room_limit_tween_4.3.gd new file mode 100644 index 0000000..970c52e --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/2D/2d_room_limit_tween_4.3.gd @@ -0,0 +1,36 @@ +extends Node2D + +@onready var pcam_room_left: PhantomCamera2D = %RoomLeftPhantomCamera2D +@onready var pcam_room_centre: PhantomCamera2D = %RoomCentrePhantomCamera2D +@onready var pcam_room_right: PhantomCamera2D = %RoomRightPhantomCamera2D + +@onready var player: Node2D = %CharacterBody2D + +@onready var area_2d_room_left: Area2D = %RoomLeftArea2D +@onready var area_2d_room_centre: Area2D = %RoomCentreArea2D +@onready var area_2d_room_right: Area2D = %RoomRightArea2D + + +func _ready(): + pcam_room_left.set_follow_offset(Vector2(0, -80)) + pcam_room_right.set_follow_offset(Vector2(0, -80)) + + area_2d_room_left.body_entered.connect(_on_body_entered.bind(pcam_room_left)) + area_2d_room_centre.body_entered.connect(_on_body_entered.bind(pcam_room_centre)) + area_2d_room_right.body_entered.connect(_on_body_entered.bind(pcam_room_right)) + + area_2d_room_left.body_exited.connect(_on_body_exited.bind(pcam_room_left)) + area_2d_room_centre.body_exited.connect(_on_body_exited.bind(pcam_room_centre)) + area_2d_room_right.body_exited.connect(_on_body_exited.bind(pcam_room_right)) + + +func _on_body_entered(body: Node2D, pcam: PhantomCamera2D) -> void: + if body == player: + pcam.set_follow_target(player) + pcam.set_priority(20) + + +func _on_body_exited(body: Node2D, pcam: PhantomCamera2D) -> void: + if body == player: + pcam.set_priority(0) + pcam.set_follow_target(null) diff --git a/godot/addons/phantom_camera/examples/scripts/2D/2d_trigger_area.gd b/godot/addons/phantom_camera/examples/scripts/2D/2d_trigger_area.gd new file mode 100644 index 0000000..db0209c --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/2D/2d_trigger_area.gd @@ -0,0 +1,16 @@ +extends Area2D + +@export var area_pcam: PhantomCamera2D + +func _ready() -> void: + connect("area_entered", _entered_area) + connect("area_exited", _exited_area) + +func _entered_area(area_2d: Area2D) -> void: + if area_2d.get_parent() is CharacterBody2D: + area_pcam.set_priority(20) + +func _exited_area(area_2d: Area2D) -> void: + if area_2d.get_parent() is CharacterBody2D: + area_pcam.set_priority(0) + diff --git a/godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d.gd b/godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d.gd new file mode 100644 index 0000000..8003bb3 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d.gd @@ -0,0 +1,189 @@ +extends CharacterBody2D + +@onready var _player_area2d = %PlayerArea2D +@onready var _player_visuals: Node2D = %PlayerVisuals +@onready var _player_sprite: Sprite2D = %PlayerSprite +@onready var _interaction_prompt: Panel = %InteractionPrompt +@onready var _ui_sign: Control +@onready var _dark_overlay: ColorRect = %DarkOverlay + +const KEY_STRINGNAME: StringName = "Key" +const ACTION_STRINGNAME: StringName = "Action" +const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left" +const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right" + +const SPEED = 350.0 +const JUMP_VELOCITY = -750.0 + +# Get the gravity from the project settings to be synced with RigidBody nodes. +var gravity: int = 2400 +var _is_interactive: bool +var _can_open_inventory: bool +var _movement_disabled: bool +var tween: Tween +var _interactive_UI: Control +var _active_pcam: PhantomCamera2D + +var _physics_body_trans_last: Transform2D +var _physics_body_trans_current: Transform2D + +enum InteractiveType { + NONE = 0, + ITEM = 1, + INVENTORY = 2, +} +var _interactive_object: InteractiveType = InteractiveType.NONE + +var InputMovementDic: Dictionary = { + INPUT_MOVE_LEFT_STRINGNAME: { + KEY_STRINGNAME: KEY_A, + ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME + }, + INPUT_MOVE_RIGHT_STRINGNAME: { + KEY_STRINGNAME: KEY_D, + ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME + }, +} + + +func _ready() -> void: + _player_area2d.body_shape_entered.connect(_show_prompt) + _player_area2d.body_shape_exited.connect(_hide_prompt) + + _ui_sign = owner.get_node("%UISign") + + for input in InputMovementDic: + var key_val = InputMovementDic[input].get(KEY_STRINGNAME) + var action_val = InputMovementDic[input].get(ACTION_STRINGNAME) + + var movement_input = InputEventKey.new() + movement_input.physical_keycode = key_val + InputMap.add_action(action_val) + InputMap.action_add_event(action_val, movement_input) + + _player_visuals.top_level = true + + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor >= 3: + printerr("Please run the other 2D example scenes, in the 2D-4.3 directory, for more up-to-date example setups.") + + +func _unhandled_input(event: InputEvent) -> void: + if _is_interactive: + if Input.is_physical_key_pressed(KEY_F): + if tween: + tween.kill() + + if not _movement_disabled: + tween = get_tree().create_tween() + + _movement_disabled = true + _active_pcam.set_priority(10) + + _show_interactive_node(_interactive_UI) + _interactive_node_logic() + + else: + _hide_interactive_node(_interactive_UI) + _interactive_node_logic() + + + if Input.is_physical_key_pressed(KEY_ESCAPE) and _movement_disabled: + _hide_interactive_node(_interactive_UI) + _interactive_node_logic() + + +func _show_interactive_node(UI: Control) -> void: + UI.modulate.a = 0 + UI.visible = true + tween.tween_property(UI, "modulate", Color.WHITE, 1).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CIRC) + + +func _hide_interactive_node(UI: Control) -> void: + _movement_disabled = false + _active_pcam.set_priority(0) + UI.visible = false + + +func _interactive_node_logic() -> void: + match _interactive_object: + 2: + if _movement_disabled: + _dark_overlay.set_visible(true) + else: + _dark_overlay.set_visible(false) + + +func _physics_process(delta: float) -> void: + _physics_body_trans_last = _physics_body_trans_current + _physics_body_trans_current = global_transform + + if not is_on_floor(): + velocity.y += gravity * delta + + if Input.is_action_just_pressed("ui_accept") and is_on_floor(): + velocity.y = JUMP_VELOCITY + + if _movement_disabled: return + + var input_dir: = Input.get_axis( + INPUT_MOVE_LEFT_STRINGNAME, + INPUT_MOVE_RIGHT_STRINGNAME + ) + + if input_dir: + velocity.x = input_dir * SPEED + if input_dir > 0: + _player_sprite.set_flip_h(false) + elif input_dir < 0: + _player_sprite.set_flip_h(true) + else: + velocity.x = move_toward(velocity.x, 0, SPEED) + + move_and_slide() + + +func _process(delta) -> void: + _player_visuals.global_position = _physics_body_trans_last.interpolate_with( + _physics_body_trans_current, + Engine.get_physics_interpolation_fraction() + ).origin + + +func _show_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void: + if body is TileMap: + var tile_map: TileMap = body + + var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid) + var cell_data: TileData = tile_map.get_cell_tile_data(1, tile_coords) + + if cell_data: + var cell_data_type: StringName = cell_data.get_custom_data("Type") +# var cell_global_pos: Vector2 = tile_map.to_global(tile_map.map_to_local(tile_coords)) + _is_interactive = true + _interaction_prompt.set_visible(true) + + match cell_data_type: + "Sign": + _interactive_UI = owner.get_node("%UISign") + _active_pcam = %ItemFocusPhantomCamera2D + _interactive_object = InteractiveType.ITEM + "Inventory": + _interactive_UI = owner.get_node("%UIInventory") + _interactive_object = InteractiveType.INVENTORY + _active_pcam = %InventoryPhantomCamera2D + + +func _hide_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void: + if body is TileMap: + var tile_map: TileMap = body + + var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid) + var cell_data: TileData = tile_map.get_cell_tile_data(1, tile_coords) + + if cell_data: + _interaction_prompt.set_visible(false) + _is_interactive = false + _interactive_UI = null + _interactive_object = InteractiveType.NONE + _active_pcam = null diff --git a/godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d_4.3.gd b/godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d_4.3.gd new file mode 100644 index 0000000..41ab5e2 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/2D/player_character_body_2d_4.3.gd @@ -0,0 +1,179 @@ +extends CharacterBody2D + +@onready var _player_area2d = %PlayerArea2D +@onready var _player_visuals: Node2D = %PlayerVisuals +@onready var _player_sprite: Sprite2D = %PlayerSprite +@onready var _interaction_prompt: Panel = %InteractionPrompt +@onready var _ui_sign: Control +@onready var _dark_overlay: ColorRect = %DarkOverlay +@onready var _noise_emitter: PhantomCameraNoiseEmitter2D + +const KEY_STRINGNAME: StringName = "Key" +const ACTION_STRINGNAME: StringName = "Action" +const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left" +const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right" + +const SPEED = 350.0 +const JUMP_VELOCITY = -750.0 + +# Get the gravity from the project settings to be synced with RigidBody nodes. +var gravity: int = 2400 +var _is_interactive: bool +var _can_open_inventory: bool +var _movement_disabled: bool +var tween: Tween +var _interactive_UI: Control +var _active_pcam: PhantomCamera2D + +enum InteractiveType { + NONE = 0, + ITEM = 1, + INVENTORY = 2, +} +var _interactive_object: InteractiveType = InteractiveType.NONE + +var InputMovementDic: Dictionary = { + INPUT_MOVE_LEFT_STRINGNAME: { + KEY_STRINGNAME: KEY_A, + ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME + }, + INPUT_MOVE_RIGHT_STRINGNAME: { + KEY_STRINGNAME: KEY_D, + ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME + }, +} + + +func _ready() -> void: + _player_area2d.body_shape_entered.connect(_show_prompt) + _player_area2d.body_shape_exited.connect(_hide_prompt) + + _ui_sign = owner.get_node("%UISign") + + for input in InputMovementDic: + var key_val = InputMovementDic[input].get(KEY_STRINGNAME) + var action_val = InputMovementDic[input].get(ACTION_STRINGNAME) + + var movement_input = InputEventKey.new() + movement_input.physical_keycode = key_val + InputMap.add_action(action_val) + InputMap.action_add_event(action_val, movement_input) + + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor < 3: + printerr("This scene is designed to only work properly in Godot 4.3 or later that supports 2D Physics Interpolation.") + printerr("Please run the other 2D example scenes in the other directory.") + + +func _unhandled_input(event: InputEvent) -> void: + if _is_interactive: + if Input.is_physical_key_pressed(KEY_F): + if tween: + tween.kill() + + if not _movement_disabled: + tween = get_tree().create_tween() + + _movement_disabled = true + _active_pcam.set_priority(10) + + _show_interactive_node(_interactive_UI) + _interactive_node_logic() + + else: + _hide_interactive_node(_interactive_UI) + _interactive_node_logic() + + + if Input.is_physical_key_pressed(KEY_ESCAPE) and _movement_disabled: + _hide_interactive_node(_interactive_UI) + _interactive_node_logic() + + if Input.is_physical_key_pressed(KEY_Q): + if get_node_or_null("%PlayerPhantomCameraNoiseEmitter2D"): + %PlayerPhantomCameraNoiseEmitter2D.emit() + + +func _show_interactive_node(UI: Control) -> void: + UI.modulate.a = 0 + UI.visible = true + tween.tween_property(UI, "modulate", Color.WHITE, 1).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CIRC) + + +func _hide_interactive_node(UI: Control) -> void: + _movement_disabled = false + _active_pcam.set_priority(0) + UI.visible = false + + +func _interactive_node_logic() -> void: + match _interactive_object: + 2: + if _movement_disabled: + _dark_overlay.set_visible(true) + else: + _dark_overlay.set_visible(false) + + +func _physics_process(delta: float) -> void: + if not is_on_floor(): + velocity.y += gravity * delta + + if Input.is_action_just_pressed("ui_accept") and is_on_floor(): + velocity.y = JUMP_VELOCITY + + if _movement_disabled: return + + var input_dir: = Input.get_axis( + INPUT_MOVE_LEFT_STRINGNAME, + INPUT_MOVE_RIGHT_STRINGNAME + ) + + if input_dir: + velocity.x = input_dir * SPEED + if input_dir > 0: + _player_sprite.set_flip_h(false) + elif input_dir < 0: + _player_sprite.set_flip_h(true) + else: + velocity.x = move_toward(velocity.x, 0, SPEED) + + move_and_slide() + + +func _show_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void: + if body.is_class("TileMapLayer"): # TODO - Using string reference to support Godot 4.2 + var tile_map := body + var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid) + var cell_data: TileData = tile_map.get_cell_tile_data(tile_coords) + + if cell_data: + var cell_data_type: StringName = cell_data.get_custom_data("Type") +# var cell_global_pos: Vector2 = tile_map.to_global(tile_map.map_to_local(tile_coords)) + _is_interactive = true + _interaction_prompt.set_visible(true) + + match cell_data_type: + "Sign": + _interactive_UI = owner.get_node("%UISign") + _active_pcam = %ItemFocusPhantomCamera2D + _interactive_object = InteractiveType.ITEM + "Inventory": + _interactive_UI = owner.get_node("%UIInventory") + _interactive_object = InteractiveType.INVENTORY + _active_pcam = %InventoryPhantomCamera2D + + +func _hide_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void: + if body.is_class("TileMapLayer"): # TODO - Using string reference to support Godot 4.2 + var tile_map := body + + var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid) + var cell_data: TileData = tile_map.get_cell_tile_data(tile_coords) + + if cell_data: + _interaction_prompt.set_visible(false) + _is_interactive = false + _interactive_UI = null + _interactive_object = InteractiveType.NONE + _active_pcam = null diff --git a/godot/addons/phantom_camera/examples/scripts/3D/3d_trigger_area.gd b/godot/addons/phantom_camera/examples/scripts/3D/3d_trigger_area.gd new file mode 100644 index 0000000..4fc9764 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/3d_trigger_area.gd @@ -0,0 +1,26 @@ +extends Area3D + +@export var area_pcam: PhantomCamera3D + +var initial_camera_position: Vector3 +var initial_camera_rotation: Vector3 + +var tween: Tween +var tween_duration: float = 0.9 + + +func _ready() -> void: + connect("area_entered", _entered_area) + connect("area_exited", _exited_area) + + +func _entered_area(area_3D: Area3D) -> void: + if area_3D.get_parent() is CharacterBody3D: + area_pcam.set_priority(20) + + +func _exited_area(area_3D: Area3D) -> void: + if area_3D.get_parent() is CharacterBody3D: + area_pcam.set_priority(0) + + diff --git a/godot/addons/phantom_camera/examples/scripts/3D/npc.gd b/godot/addons/phantom_camera/examples/scripts/3D/npc.gd new file mode 100644 index 0000000..3d9a523 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/npc.gd @@ -0,0 +1,71 @@ +extends Node3D + +@onready var npc_pcam: PhantomCamera3D = %NPCPhantomCamera3D +@onready var dialogueArea: Area3D = %NPCInteractionArea3D +@onready var dialogueLabel3D: Label3D = %NPCDialogueExampleLabel + +@onready var player: CharacterBody3D = %PlayerCharacterBody3D + +@onready var move_to_location: Vector3 = %MoveToLocation.get_global_position() + +var dialogue_label_initial_position: Vector3 +var dialogue_label_initial_rotation: Vector3 + +var tween: Tween +var tween_duration: float = 0.9 +var tween_transition: Tween.TransitionType = Tween.TRANS_QUAD + +var interactable: bool +var is_interacting: bool + +func _ready() -> void: + dialogueArea.connect("area_entered", _interactable) + dialogueArea.connect("area_exited", _not_interactable) + + dialogueLabel3D.set_visible(false) + + dialogue_label_initial_position = dialogueLabel3D.get_global_position() + dialogue_label_initial_rotation = dialogueLabel3D.get_global_rotation() + + npc_pcam.tween_completed.connect(_on_tween_started) + + + +func _on_tween_started() -> void: + player.movement_enabled = false + + +func _interactable(area_3D: Area3D) -> void: + if area_3D.get_parent() is CharacterBody3D: + dialogueLabel3D.set_visible(true) + interactable = true + + var tween: Tween = get_tree().create_tween().set_trans(tween_transition).set_ease(Tween.EASE_IN_OUT).set_loops() + tween.tween_property(dialogueLabel3D, "global_position", dialogue_label_initial_position - Vector3(0, -0.2, 0), tween_duration) + tween.tween_property(dialogueLabel3D, "position", dialogue_label_initial_position, tween_duration) + + +func _not_interactable(area_3D: Area3D) -> void: + if area_3D.get_parent() is CharacterBody3D: + dialogueLabel3D.set_visible(false) + interactable = false + + +func _input(event) -> void: + if not interactable: return + + if event is InputEventKey and event.pressed: + if event.keycode == KEY_F: + var tween: Tween = get_tree().create_tween() \ + .set_parallel(true) \ + .set_trans(Tween.TRANS_QUART) \ + .set_ease(Tween.EASE_IN_OUT) + if not is_interacting: + npc_pcam.priority = 20 + tween.tween_property(player, "global_position", move_to_location, 0.6).set_trans(tween_transition) + tween.tween_property(dialogueLabel3D, "rotation", Vector3(deg_to_rad(-20), deg_to_rad(53), 0), 0.6).set_trans(tween_transition) + else: + npc_pcam.priority = 0 + tween.tween_property(dialogueLabel3D, "rotation", dialogue_label_initial_rotation, 0.9) + player.movement_enabled = true + is_interacting = !is_interacting diff --git a/godot/addons/phantom_camera/examples/scripts/3D/path_follow.gd b/godot/addons/phantom_camera/examples/scripts/3D/path_follow.gd new file mode 100644 index 0000000..8535e4c --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/path_follow.gd @@ -0,0 +1,17 @@ +extends Node + +@export var path_pcam: PhantomCamera3D + +func _ready() -> void: + connect("area_entered", _entered_area) + connect("area_exited", _exited_area) + + +func _entered_area(area_3D: Area3D) -> void: + if area_3D.get_parent() is CharacterBody3D: + path_pcam.set_priority(20) + + +func _exited_area(area_3D: Area3D) -> void: + if area_3D.get_parent() is CharacterBody3D: + path_pcam.set_priority(0) diff --git a/godot/addons/phantom_camera/examples/scripts/3D/player_controller.gd b/godot/addons/phantom_camera/examples/scripts/3D/player_controller.gd new file mode 100644 index 0000000..b136103 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/player_controller.gd @@ -0,0 +1,103 @@ +extends CharacterBody3D + +@export var SPEED: float = 5.0 +@export var JUMP_VELOCITY: float = 4.5 +@export var enable_gravity = true + +@onready var _camera: Camera3D + +@onready var _player_visual: Node3D = %PlayerVisual + +# Get the gravity from the project settings to be synced with RigidBody nodes. +var gravity: float = 9.8 + +var movement_enabled: bool = true + +var _physics_body_trans_last: Transform3D +var _physics_body_trans_current: Transform3D + +const KEY_STRINGNAME: StringName = "Key" +const ACTION_STRINGNAME: StringName = "Action" + +const INPUT_MOVE_UP_STRINGNAME: StringName = "move_up" +const INPUT_MOVE_DOWM_STRINGNAME: StringName = "move_down" +const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left" +const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right" + +var InputMovementDic: Dictionary = { + INPUT_MOVE_UP_STRINGNAME: { + KEY_STRINGNAME: KEY_W, + ACTION_STRINGNAME: INPUT_MOVE_UP_STRINGNAME + }, + INPUT_MOVE_DOWM_STRINGNAME: { + KEY_STRINGNAME: KEY_S, + ACTION_STRINGNAME: INPUT_MOVE_DOWM_STRINGNAME + }, + INPUT_MOVE_LEFT_STRINGNAME: { + KEY_STRINGNAME: KEY_A, + ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME + }, + INPUT_MOVE_RIGHT_STRINGNAME: { + KEY_STRINGNAME: KEY_D, + ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME + }, +} + + +func _ready() -> void: + for input in InputMovementDic: + var key_val = InputMovementDic[input].get(KEY_STRINGNAME) + var action_val = InputMovementDic[input].get(ACTION_STRINGNAME) + + _camera = owner.get_node("%MainCamera3D") + + var movement_input = InputEventKey.new() + movement_input.physical_keycode = key_val + InputMap.add_action(action_val) + InputMap.action_add_event(action_val, movement_input) + + _player_visual.top_level = true + + +func _physics_process(delta: float) -> void: + _physics_body_trans_last = _physics_body_trans_current + _physics_body_trans_current = global_transform + + # Add the gravity. + if enable_gravity and not is_on_floor(): + velocity.y -= gravity * delta + + if not movement_enabled: return + + # Get the input direction and handle the movement/deceleration. + # As good practice, you should replace UI actions with custom gameplay actions. + var input_dir: Vector2 = Input.get_vector( + INPUT_MOVE_LEFT_STRINGNAME, + INPUT_MOVE_RIGHT_STRINGNAME, + INPUT_MOVE_UP_STRINGNAME, + INPUT_MOVE_DOWM_STRINGNAME + ) + + var cam_dir: Vector3 = -_camera.global_transform.basis.z + + var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() + if direction: + var move_dir: Vector3 = Vector3.ZERO + move_dir.x = direction.x + move_dir.z = direction.z + + move_dir = move_dir.rotated(Vector3.UP, _camera.rotation.y).normalized() + velocity.x = move_dir.x * SPEED + velocity.z = move_dir.z * SPEED + else: + velocity.x = move_toward(velocity.x, 0, SPEED) + velocity.z = move_toward(velocity.z, 0, SPEED) + + move_and_slide() + + +func _process(_delta: float) -> void: + _player_visual.global_transform = _physics_body_trans_last.interpolate_with( + _physics_body_trans_current, + Engine.get_physics_interpolation_fraction() + ) diff --git a/godot/addons/phantom_camera/examples/scripts/3D/player_controller_4.4.gd b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_4.4.gd new file mode 100644 index 0000000..e907eca --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_4.4.gd @@ -0,0 +1,84 @@ +extends CharacterBody3D + +@export var SPEED: float = 5.0 +@export var JUMP_VELOCITY: float = 4.5 +@export var enable_gravity = true + +@onready var _camera: Camera3D + +# Get the gravity from the project settings to be synced with RigidBody nodes. +var gravity: float = 9.8 + +var movement_enabled: bool = true + +const KEY_STRINGNAME: StringName = "Key" +const ACTION_STRINGNAME: StringName = "Action" + +const INPUT_MOVE_UP_STRINGNAME: StringName = "move_up" +const INPUT_MOVE_DOWM_STRINGNAME: StringName = "move_down" +const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left" +const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right" + +var InputMovementDic: Dictionary = { + INPUT_MOVE_UP_STRINGNAME: { + KEY_STRINGNAME: KEY_W, + ACTION_STRINGNAME: INPUT_MOVE_UP_STRINGNAME + }, + INPUT_MOVE_DOWM_STRINGNAME: { + KEY_STRINGNAME: KEY_S, + ACTION_STRINGNAME: INPUT_MOVE_DOWM_STRINGNAME + }, + INPUT_MOVE_LEFT_STRINGNAME: { + KEY_STRINGNAME: KEY_A, + ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME + }, + INPUT_MOVE_RIGHT_STRINGNAME: { + KEY_STRINGNAME: KEY_D, + ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME + }, +} + + +func _ready() -> void: + for input in InputMovementDic: + var key_val = InputMovementDic[input].get(KEY_STRINGNAME) + var action_val = InputMovementDic[input].get(ACTION_STRINGNAME) + + _camera = owner.get_node("%MainCamera3D") + + var movement_input = InputEventKey.new() + movement_input.physical_keycode = key_val + InputMap.add_action(action_val) + InputMap.action_add_event(action_val, movement_input) + + +func _physics_process(delta: float) -> void: + # Add the gravity. + if enable_gravity and not is_on_floor(): + velocity.y -= gravity * delta + + if not movement_enabled: return + + # Get the input direction and handle the movement/deceleration. + # As good practice, you should replace UI actions with custom gameplay actions. + var input_dir: Vector2 = Input.get_vector( + INPUT_MOVE_LEFT_STRINGNAME, + INPUT_MOVE_RIGHT_STRINGNAME, + INPUT_MOVE_UP_STRINGNAME, + INPUT_MOVE_DOWM_STRINGNAME + ) + + var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() + if direction: + var move_dir: Vector3 = Vector3.ZERO + move_dir.x = direction.x + move_dir.z = direction.z + + move_dir = move_dir.rotated(Vector3.UP, _camera.rotation.y).normalized() + velocity.x = move_dir.x * SPEED + velocity.z = move_dir.z * SPEED + else: + velocity.x = move_toward(velocity.x, 0, SPEED) + velocity.z = move_toward(velocity.z, 0, SPEED) + + move_and_slide() diff --git a/godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person.gd b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person.gd new file mode 100644 index 0000000..7e2da3f --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person.gd @@ -0,0 +1,54 @@ +extends "player_controller.gd" + +@onready var _player_pcam: PhantomCamera3D = %PlayerPhantomCamera3D + +@onready var _player_character: CharacterBody3D = %PlayerCharacterBody3D + +@export var mouse_sensitivity: float = 0.05 + +@export var min_pitch: float = -89.9 +@export var max_pitch: float = 50 + +@export var min_yaw: float = 0 +@export var max_yaw: float = 360 + +@export var run_noise: PhantomCameraNoise3D + +func _ready() -> void: + super() + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"): + %EmitterTip.visible = true + + +func _physics_process(delta: float) -> void: + super(delta) + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventKey: + if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"): + if event.keycode == KEY_Q and event.is_pressed(): + %PlayerPhantomCameraNoiseEmitter3D.emit() + + if event is InputEventMouseMotion: + var pcam_rotation_degrees: Vector3 + + # Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor + pcam_rotation_degrees = _player_pcam.rotation_degrees + + # Change the X rotation + pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity + + # Clamp the rotation in the X axis so it go over or under the target + pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch) + + # Change the Y rotation value + pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity + + # Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively + pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw) + + # Change the SpringArm3D node's rotation and rotate around its target + _player_pcam.rotation_degrees = pcam_rotation_degrees diff --git a/godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person_4.4.gd b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person_4.4.gd new file mode 100644 index 0000000..33e4601 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_first_person_4.4.gd @@ -0,0 +1,54 @@ +extends "player_controller_4.4.gd" + +@onready var _player_pcam: PhantomCamera3D = %PlayerPhantomCamera3D + +@onready var _player_character: CharacterBody3D = %PlayerCharacterBody3D + +@export var mouse_sensitivity: float = 0.05 + +@export var min_pitch: float = -89.9 +@export var max_pitch: float = 50 + +@export var min_yaw: float = 0 +@export var max_yaw: float = 360 + +@export var run_noise: PhantomCameraNoise3D + +func _ready() -> void: + super() + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"): + %EmitterTip.visible = true + + +func _physics_process(delta: float) -> void: + super(delta) + + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventKey: + if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"): + if event.keycode == KEY_Q and event.is_pressed(): + %PlayerPhantomCameraNoiseEmitter3D.emit() + + if event is InputEventMouseMotion: + var pcam_rotation_degrees: Vector3 + + # Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor + pcam_rotation_degrees = _player_pcam.rotation_degrees + + # Change the X rotation + pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity + + # Clamp the rotation in the X axis so it go over or under the target + pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch) + + # Change the Y rotation value + pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity + + # Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively + pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw) + + # Change the SpringArm3D node's rotation and rotate around its target + _player_pcam.rotation_degrees = pcam_rotation_degrees diff --git a/godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person.gd b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person.gd new file mode 100644 index 0000000..f5d5579 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person.gd @@ -0,0 +1,87 @@ +extends "player_controller.gd" + +@onready var _player_pcam: PhantomCamera3D +@onready var _aim_pcam: PhantomCamera3D +@onready var _player_direction: Node3D = %PlayerDirection +@onready var _ceiling_pcam: PhantomCamera3D + +@export var mouse_sensitivity: float = 0.05 + +@export var min_pitch: float = -89.9 +@export var max_pitch: float = 50 + +@export var min_yaw: float = 0 +@export var max_yaw: float = 360 + + + +func _ready() -> void: + super() + + _player_pcam = owner.get_node("%PlayerPhantomCamera3D") + _aim_pcam = owner.get_node("%PlayerAimPhantomCamera3D") + _ceiling_pcam = owner.get_node("%CeilingPhantomCamera3D") + + if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + +func _physics_process(delta: float) -> void: + super(delta) + + if velocity.length() > 0.2: + var look_direction: Vector2 = Vector2(velocity.z, velocity.x) + _player_direction.rotation.y = look_direction.angle() + + +func _unhandled_input(event: InputEvent) -> void: + if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON: + var active_pcam: PhantomCamera3D + + _set_pcam_rotation(_player_pcam, event) + _set_pcam_rotation(_aim_pcam, event) + if _player_pcam.get_priority() > _aim_pcam.get_priority(): + _toggle_aim_pcam(event) + else: + _toggle_aim_pcam(event) + + if event is InputEventKey and event.pressed: + if event.keycode == KEY_SPACE: + if _ceiling_pcam.get_priority() < 30 and _player_pcam.is_active(): + _ceiling_pcam.set_priority(30) + else: + _ceiling_pcam.set_priority(1) + + +func _set_pcam_rotation(pcam: PhantomCamera3D, event: InputEvent) -> void: + if event is InputEventMouseMotion: + var pcam_rotation_degrees: Vector3 + + # Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor + pcam_rotation_degrees = pcam.get_third_person_rotation_degrees() + + # Change the X rotation + pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity + + # Clamp the rotation in the X axis so it go over or under the target + pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch) + + # Change the Y rotation value + pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity + + # Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively + pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw) + + # Change the SpringArm3D node's rotation and rotate around its target + pcam.set_third_person_rotation_degrees(pcam_rotation_degrees) + + +func _toggle_aim_pcam(event: InputEvent) -> void: + if event is InputEventMouseButton \ + and event.is_pressed() \ + and event.button_index == 2 \ + and (_player_pcam.is_active() or _aim_pcam.is_active()): + if _player_pcam.get_priority() > _aim_pcam.get_priority(): + _aim_pcam.set_priority(30) + else: + _aim_pcam.set_priority(0) diff --git a/godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person_4.4.gd b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person_4.4.gd new file mode 100644 index 0000000..d0d56d4 --- /dev/null +++ b/godot/addons/phantom_camera/examples/scripts/3D/player_controller_third_person_4.4.gd @@ -0,0 +1,86 @@ +extends "player_controller_4.4.gd" + +@onready var _player_pcam: PhantomCamera3D +@onready var _aim_pcam: PhantomCamera3D +@onready var _player_direction: Node3D = %PlayerDirection +@onready var _ceiling_pcam: PhantomCamera3D + +@export var mouse_sensitivity: float = 0.05 + +@export var min_pitch: float = -89.9 +@export var max_pitch: float = 50 + +@export var min_yaw: float = 0 +@export var max_yaw: float = 360 + + +func _ready() -> void: + super() + + _player_pcam = owner.get_node("%PlayerPhantomCamera3D") + _aim_pcam = owner.get_node("%PlayerAimPhantomCamera3D") + _ceiling_pcam = owner.get_node("%CeilingPhantomCamera3D") + + if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + + +func _physics_process(delta: float) -> void: + super(delta) + + if velocity.length() > 0.2: + var look_direction: Vector2 = Vector2(velocity.z, velocity.x) + _player_direction.rotation.y = look_direction.angle() + + +func _unhandled_input(event: InputEvent) -> void: + if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON: + var active_pcam: PhantomCamera3D + + _set_pcam_rotation(_player_pcam, event) + _set_pcam_rotation(_aim_pcam, event) + if _player_pcam.get_priority() > _aim_pcam.get_priority(): + _toggle_aim_pcam(event) + else: + _toggle_aim_pcam(event) + + if event is InputEventKey and event.pressed: + if event.keycode == KEY_SPACE: + if _ceiling_pcam.get_priority() < 30 and _player_pcam.is_active(): + _ceiling_pcam.set_priority(30) + else: + _ceiling_pcam.set_priority(1) + + +func _set_pcam_rotation(pcam: PhantomCamera3D, event: InputEvent) -> void: + if event is InputEventMouseMotion: + var pcam_rotation_degrees: Vector3 + + # Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor + pcam_rotation_degrees = pcam.get_third_person_rotation_degrees() + + # Change the X rotation + pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity + + # Clamp the rotation in the X axis so it go over or under the target + pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch) + + # Change the Y rotation value + pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity + + # Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively + pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw) + + # Change the SpringArm3D node's rotation and rotate around its target + pcam.set_third_person_rotation_degrees(pcam_rotation_degrees) + + +func _toggle_aim_pcam(event: InputEvent) -> void: + if event is InputEventMouseButton \ + and event.is_pressed() \ + and event.button_index == 2 \ + and (_player_pcam.is_active() or _aim_pcam.is_active()): + if _player_pcam.get_priority() > _aim_pcam.get_priority(): + _aim_pcam.set_priority(30) + else: + _aim_pcam.set_priority(0) diff --git a/godot/addons/phantom_camera/examples/textures/2D/inventory_container.png b/godot/addons/phantom_camera/examples/textures/2D/inventory_container.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd51782c1814bfcb8e61ac54b642432a3870030 GIT binary patch literal 68739 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 z zBiT8DSUC&`u>f4{=YZT1I}^a)g`wNcHBq0?_k#4<2f-N5Fqhgi)d$lPvtB0q0^swO zf#-5MARZOl?N1ZqdP%kpw(-1j*7^XypNX`a=~d&gu}Sis5C9TB z8U}={;7;akTOhn)N(|ssKnwEE!)0Ocbqj>b5YnCeYU2FcPGAP1i_k-p0LkDXwPO4L z$3Qs@8zS!YxJ=ISNUWP(5^Gmis|P-h4n5Lqi3{>nm!F$-yhRHPX9I7T*MPCmDXXHO zSYbT1%d6F|6vu?3@1L(kd%$XQ2+T~|CEo{`^g5@3+M9zX`+lfvBI_u<6ceVSr zTW-#g7~k)q6>@a%JOH{yeX@PgzPjN^>BDsr6_cXpdnUk74v*&?-*^yhhVHQXc$WRG z%}#?(eL)Lav1VpNFX5(W6r*e8{0HErELHsyu%9UL%`G^$waMOrvV?2!RPj8ROaQd! zYtLCwi<)N!VRJ5J*>Nl9ZBR;0K{mpa(7;-EH8O{Z$l!mxPNknI_=;yY**i4(Z2na7 zDC}Uo5gxa^@~TWR^hE+UMzj9ZjBinW5pgpZixdP;VUi9M zVtxD9fUsV>iI)jCRQCPt-X-eqvjw%Ahk!R9nvtubvodbc{}T!xa&dr)KfNLbIh*2? zObg@XYwkl&v%f7Y2DGhJ?!fa@6BN{wq*~x~~ci zEEKSt^>15=9HWnk5nslZju3_&X5r|;KP4bVsEUcIPX{NtSadRjAKdN`%bFW;fY=4Q z=^~%~ZnbDsu%0_Pd$EzNV`Mpb)i2dZ^we}CLib*2`}kLW0-R}GQ`SoCa50M=R2s5l z)3r;XOKf|HIbGwb@H45HMHrJuy7z-O^S{lYij(W2@p*-&F0oAt9%e*CyLHX+2Gp$} zzw(Wy&Ds9_lB=&cB^N$vn8Nd0(~~(0pIS1Q5V>WGj}9v*kx(PPzgvTF`nuB^C{}y# z4p*Q46S|QJ2})J0I1MVbDl+5-=32_e>B&a0jLP&Vcrz@TO zG>$sHcu>eA9lprT!`O^*im8nkjO4tiMWwvo zu5y2HuUTzRRRjF#+dRi!`ol@~6b{#bCSQ}ieA}qRw#W}nQwW?y;d#6Gr;Gi@vi+3~ z|2*A$!zIH<2u|xl1ED+C=4;7H9j7q81Y6g}!r%7ttD>-*zC@!ItBU;&E)z+_{> z%asNxp2n2$arIyIN~9hes)x;y*s-EC(qPhTh$J--3e1JwQdJ*(H11q%w!BlJA6YRa z3(?~K__W1N1C+r}WxmpOh}UI2-xl7Vt@II$|J%JZVc=NemvKK?vGA^X`cYncA!7R` z5onozM`0csUDl3ZXze@*%aX51)UxrkL5MslJ4L4vg@#rlQnE!~3$^wy^i*aWq!53$ zvXy<&Tt1qeO^y(8D5<&8p3DepV#R*v9wu}FMf04v)g~FcuJwaOZUv z{G32GdqdLt;OW{utNY(IHu}&DrcuX%Z=9qwY+sE)uss}*u#2ga&TbX&XYGH!Q1j)YwAMNCNLef|Di?ju?s%DUkg0sx;E(r^iW9H9A(Iz=c`9yly&LVmkqg>_- zCFL0-qM_E~x%sUK5|wGzE7>duxnp9Fy-G?r4xx>e(Yl;RbVZlVF z(*4zqETaBNha=W{9LS~h?|wg;1C@Zcj804}^UM0|{j)F-m$1Ewd&NWoKdc30C6y#9 I#Eb*}4+*yQXaE2J literal 0 HcmV?d00001 diff --git a/godot/addons/phantom_camera/examples/textures/2D/level_spritesheet.png.import b/godot/addons/phantom_camera/examples/textures/2D/level_spritesheet.png.import new file mode 100644 index 0000000..520372a --- /dev/null +++ b/godot/addons/phantom_camera/examples/textures/2D/level_spritesheet.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c77npili4pel4" +path="res://.godot/imported/level_spritesheet.png-26a44dd21a040a5480d5ccba54377d99.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/examples/textures/2D/level_spritesheet.png" +dest_files=["res://.godot/imported/level_spritesheet.png-26a44dd21a040a5480d5ccba54377d99.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/godot/addons/phantom_camera/examples/textures/2D/phantom_camera_2d_sprite.png b/godot/addons/phantom_camera/examples/textures/2D/phantom_camera_2d_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..2012b3ad9fe1d9a52d62b126548c02bbc7ca9abe GIT binary patch literal 1584 zcmV-02G9A4P)jT;RVtNwE}H)5boaS5z??aAzGno4;Ma?r+>?y`3_;`t zU>*^2bf>KErdJ5iqR$spPW|AZE*zl(GE&9jCUq=Z%g&*T*xLoyF=CECtLS|Z57hO^q;Zc?3RXr;)jjQs&p;*kaL zn5T!ihBTnzaIn3&4++y3fR{OyS@=xvBnK&>6l}bHvDAPB=??*32=pd=-f%A5I2a-;@@~l2pI_$mmh8-bPl@@t_#wCs&BB3yg zQnc7NfB@Kyx1_zU0M-PEmCnSh8k5u^A_+h=s52XbjlchSTNT3O&wJkEMwGNTcU(&Q z2#g-AXbOqdSI?JDM%^odAK+2s1ggJ*f15f_F~dpMb#6jPDwnqv>ih`z9liXI8D_pi(ki|U|Oj+ls7SP3uCyJ)dOUo@p?L3=( zxU5xhmdS>gK?!A(@6U9iN7zKL^Sy~oSnA691`YpP>yG(QbhAw7IxC1-08u^MUefyh zmD){Sfn8DEvD`^dBR{OC8i@ilhW&NKB7`T4PcxkL8j4S*Gz9eM!d`}pFVuOC{fohO zz#U4}f2w#{t7y26v!-j0Q2m3*aXnc`ZOEwq?3TfrfC(5MF2D;MrndeCH+n*x_72y@vH)9i1|B?Qqt7v?H>;| zdc~I~)=@kH#JQ<{P@mf7% znglVYtM5_T`yWUcDXevV7E=%v+bW=|@7azzhlI1fL{Tl+*A$Ft9{KPE)``{JcbO|#``~m + + + diff --git a/godot/addons/phantom_camera/examples/textures/2D/player_sprite.svg.import b/godot/addons/phantom_camera/examples/textures/2D/player_sprite.svg.import new file mode 100644 index 0000000..84c750b --- /dev/null +++ b/godot/addons/phantom_camera/examples/textures/2D/player_sprite.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cscjjt55iw2cu" +path="res://.godot/imported/player_sprite.svg-8862ecb19e12152eb892607676f3831f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/examples/textures/2D/player_sprite.svg" +dest_files=["res://.godot/imported/player_sprite.svg-8862ecb19e12152eb892607676f3831f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=8.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png b/godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png new file mode 100644 index 0000000000000000000000000000000000000000..a730837097daacd1e658959c81f529fcea7ff885 GIT binary patch literal 175934 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 Ani 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 literal 0 HcmV?d00001 diff --git a/godot/addons/phantom_camera/fonts/Nunito-Black.ttf.import b/godot/addons/phantom_camera/fonts/Nunito-Black.ttf.import new file mode 100644 index 0000000..8e68c5f --- /dev/null +++ b/godot/addons/phantom_camera/fonts/Nunito-Black.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://c4mm3of2mc8o5" +path="res://.godot/imported/Nunito-Black.ttf-2a374efbc207a97a99b8c70bdc4b7cbb.fontdata" + +[deps] + +source_file="res://addons/phantom_camera/fonts/Nunito-Black.ttf" +dest_files=["res://.godot/imported/Nunito-Black.ttf-2a374efbc207a97a99b8c70bdc4b7cbb.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=1 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/godot/addons/phantom_camera/fonts/Nunito-Regular.ttf b/godot/addons/phantom_camera/fonts/Nunito-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dfd0fcb40ec761ccced488d783fc77a4276548db GIT binary patch literal 131736 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

Cg|u*xfjw`p@N!J?^468a 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 + + + + + + + + + + + + + diff --git a/godot/addons/phantom_camera/icons/misc/PriorityOverride.svg.import b/godot/addons/phantom_camera/icons/misc/PriorityOverride.svg.import new file mode 100644 index 0000000..d78acf5 --- /dev/null +++ b/godot/addons/phantom_camera/icons/misc/PriorityOverride.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dy8eifa6aw2en" +path="res://.godot/imported/PriorityOverride.svg-e76e07f4bbd98169f119e17fe5f2f03f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/misc/PriorityOverride.svg" +dest_files=["res://.godot/imported/PriorityOverride.svg-e76e07f4bbd98169f119e17fe5f2f03f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_2d.svg b/godot/addons/phantom_camera/icons/phantom_camera_2d.svg new file mode 100644 index 0000000..0c67805 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_2d.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/phantom_camera/icons/phantom_camera_2d.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_2d.svg.import new file mode 100644 index 0000000..724069f --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_2d.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dchkkx4v3ikpw" +path="res://.godot/imported/phantom_camera_2d.svg-e5483cbc858fc5f95f7210b1649dff0d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_2d.svg" +dest_files=["res://.godot/imported/phantom_camera_2d.svg-e5483cbc858fc5f95f7210b1649dff0d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_3d.svg b/godot/addons/phantom_camera/icons/phantom_camera_3d.svg new file mode 100644 index 0000000..db18730 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_3d.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/phantom_camera/icons/phantom_camera_3d.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_3d.svg.import new file mode 100644 index 0000000..eedbd2f --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_3d.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c71drpb8o4prn" +path="res://.godot/imported/phantom_camera_3d.svg-41ed612e834470377fb56eebffa083fe.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_3d.svg" +dest_files=["res://.godot/imported/phantom_camera_3d.svg-41ed612e834470377fb56eebffa083fe.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg b/godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg new file mode 100644 index 0000000..282adf2 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg @@ -0,0 +1,3 @@ + + + diff --git a/godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg.import new file mode 100644 index 0000000..4b0e8bc --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dnaykbu6ue5lo" +path="res://.godot/imported/phantom_camera_camera_3d_resource.svg-f8bf8d1a5b7442fd6933bfbed999d57d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg" +dest_files=["res://.godot/imported/phantom_camera_camera_3d_resource.svg-f8bf8d1a5b7442fd6933bfbed999d57d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg b/godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg new file mode 100644 index 0000000..d791ce0 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg.import new file mode 100644 index 0000000..7b49608 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_gizmo.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://e36npe2rbxyg" +path.s3tc="res://.godot/imported/phantom_camera_gizmo.svg-ba1aacb9b1c5f4ef401d3bd3697a542b.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_gizmo.svg" +dest_files=["res://.godot/imported/phantom_camera_gizmo.svg-ba1aacb9b1c5f4ef401d3bd3697a542b.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_glow_logo.png b/godot/addons/phantom_camera/icons/phantom_camera_glow_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..41ad8de3d6dac4aeb7771d01adc69f65b7c291df GIT binary patch literal 25499 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 i`=EW$K4@P9?f(PHo+dfTz!fzB0000 \ No newline at end of file diff --git a/godot/addons/phantom_camera/icons/phantom_camera_host.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_host.svg.import new file mode 100644 index 0000000..430d67d --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_host.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://5fatldiu7dd5" +path="res://.godot/imported/phantom_camera_host.svg-3150f8f2d82ca9ecab9a3a415da21c5b.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_host.svg" +dest_files=["res://.godot/imported/phantom_camera_host.svg-3150f8f2d82ca9ecab9a3a415da21c5b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=true diff --git a/godot/addons/phantom_camera/icons/phantom_camera_logo.png b/godot/addons/phantom_camera/icons/phantom_camera_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc43e567916df70bb8f8b25a7c394b98b6c221e7 GIT binary patch literal 70905 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 + + + diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg.import new file mode 100644 index 0000000..c24e060 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b2r7mhd780y8d" +path="res://.godot/imported/phantom_camera_noise_emitter_2d.svg-1b3d37fe36964dc86a6ea6681d0772bb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg" +dest_files=["res://.godot/imported/phantom_camera_noise_emitter_2d.svg-1b3d37fe36964dc86a6ea6681d0772bb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg new file mode 100644 index 0000000..c567f6a --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg @@ -0,0 +1,4 @@ + + + + diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg.import new file mode 100644 index 0000000..de23002 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cby76y7m6xn4f" +path.s3tc="res://.godot/imported/phantom_camera_noise_emitter_3d.svg-9b90fe54aa618f65d52ac94515d41ea4.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg" +dest_files=["res://.godot/imported/phantom_camera_noise_emitter_3d.svg-9b90fe54aa618f65d52ac94515d41ea4.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg new file mode 100644 index 0000000..9b9bcb2 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg.import new file mode 100644 index 0000000..4dd736b --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dw4iy855s0atm" +path.s3tc="res://.godot/imported/phantom_camera_noise_emitter_gizmo.svg-9a593802655a8d5038c7f55deab3882d.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg" +dest_files=["res://.godot/imported/phantom_camera_noise_emitter_gizmo.svg-9a593802655a8d5038c7f55deab3882d.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg b/godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg new file mode 100644 index 0000000..d3c6deb --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg.import new file mode 100644 index 0000000..8cefc36 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_noise_resource.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://fudwitkewe70" +path="res://.godot/imported/phantom_camera_noise_resource.svg-a81ed223714edd2c0d9cfa00be0c3f58.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_noise_resource.svg" +dest_files=["res://.godot/imported/phantom_camera_noise_resource.svg-a81ed223714edd2c0d9cfa00be0c3f58.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/phantom_camera_tween.svg b/godot/addons/phantom_camera/icons/phantom_camera_tween.svg new file mode 100644 index 0000000..6956fb5 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_tween.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/godot/addons/phantom_camera/icons/phantom_camera_tween.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_tween.svg.import new file mode 100644 index 0000000..3db67fb --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_tween.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dphl04mdf3220" +path="res://.godot/imported/phantom_camera_tween.svg-16faced08ef4a5f3458264d894230dbd.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_tween.svg" +dest_files=["res://.godot/imported/phantom_camera_tween.svg-16faced08ef4a5f3458264d894230dbd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=true diff --git a/godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg b/godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg new file mode 100644 index 0000000..6d3bcd4 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg.import b/godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg.import new file mode 100644 index 0000000..c182784 --- /dev/null +++ b/godot/addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d4j4hrb7yusyq" +path="res://.godot/imported/phantom_camera_updater_panel_icon.svg-19823e6cbee8115f8b2554d0ee6e79db.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg" +dest_files=["res://.godot/imported/phantom_camera_updater_panel_icon.svg-19823e6cbee8115f8b2554d0ee6e79db.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg b/godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg new file mode 100644 index 0000000..59efad4 --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg.import b/godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg.import new file mode 100644 index 0000000..e8fb35d --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ccnsrg8hq74p2" +path="res://.godot/imported/Camera2DIcon.svg-300e6f57281180711c5ecf391104d4ba.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg" +dest_files=["res://.godot/imported/Camera2DIcon.svg-300e6f57281180711c5ecf391104d4ba.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg b/godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg new file mode 100644 index 0000000..2366c3f --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg.import b/godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg.import new file mode 100644 index 0000000..79708e2 --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dkiefpjsrj37n" +path="res://.godot/imported/Camera3DIcon.svg-4805c46004db1c89cc9443dd740693f5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg" +dest_files=["res://.godot/imported/Camera3DIcon.svg-4805c46004db1c89cc9443dd740693f5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg b/godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg new file mode 100644 index 0000000..87e3f79 --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg.import b/godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg.import new file mode 100644 index 0000000..364c4ed --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dk7omm0x44suj" +path="res://.godot/imported/SceneTypesIcon.svg-66e2255bd3398007bec03a5cbfa4d0aa.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg" +dest_files=["res://.godot/imported/SceneTypesIcon.svg-66e2255bd3398007bec03a5cbfa4d0aa.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/viewfinder/Select.svg b/godot/addons/phantom_camera/icons/viewfinder/Select.svg new file mode 100644 index 0000000..34b109b --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/Select.svg @@ -0,0 +1,3 @@ + + + diff --git a/godot/addons/phantom_camera/icons/viewfinder/Select.svg.import b/godot/addons/phantom_camera/icons/viewfinder/Select.svg.import new file mode 100644 index 0000000..81b41c9 --- /dev/null +++ b/godot/addons/phantom_camera/icons/viewfinder/Select.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rghrkoqrm2ig" +path="res://.godot/imported/Select.svg-cdf90b8b400d3b91a023b70c6a823894.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/viewfinder/Select.svg" +dest_files=["res://.godot/imported/Select.svg-cdf90b8b400d3b91a023b70c6a823894.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=2.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/icons/warning.svg b/godot/addons/phantom_camera/icons/warning.svg new file mode 100644 index 0000000..63dbedf --- /dev/null +++ b/godot/addons/phantom_camera/icons/warning.svg @@ -0,0 +1,4 @@ + + + + diff --git a/godot/addons/phantom_camera/icons/warning.svg.import b/godot/addons/phantom_camera/icons/warning.svg.import new file mode 100644 index 0000000..2895b37 --- /dev/null +++ b/godot/addons/phantom_camera/icons/warning.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cjlv0bg7byjx0" +path="res://.godot/imported/warning.svg-c1b21c265e0842bbdc9ed10735995366.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/icons/warning.svg" +dest_files=["res://.godot/imported/warning.svg-c1b21c265e0842bbdc9ed10735995366.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=2.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/phantom_camera/inspector/phantom_camera_inspector_plugin.gd b/godot/addons/phantom_camera/inspector/phantom_camera_inspector_plugin.gd new file mode 100644 index 0000000..d5a0d22 --- /dev/null +++ b/godot/addons/phantom_camera/inspector/phantom_camera_inspector_plugin.gd @@ -0,0 +1,46 @@ +@tool +extends EditorInspectorPlugin + +#var _phantom_camera_script: Script = preload("res://addons/phantom_camera/scripts/phantom_camera.gd") + + +# TODO - Enable again once work is resumed for inspector based tasks + +#func _can_handle(object) -> bool: +# return object is _phantom_camera_script + + +func _parse_category(object: Object, category: String) -> void: + + var _margin_container: MarginContainer = MarginContainer.new() + var _margin_v: float = 20 + _margin_container.add_theme_constant_override("margin_left", 10) + _margin_container.add_theme_constant_override("margin_top", _margin_v) + _margin_container.add_theme_constant_override("margin_right", 10) + _margin_container.add_theme_constant_override("margin_bottom", _margin_v) + add_custom_control(_margin_container) + + var _vbox_container: VBoxContainer = VBoxContainer.new() + _margin_container.add_child(_vbox_container) + + var align_with_view_button = Button.new() + align_with_view_button.connect("pressed", _align_camera_with_view.bind(object)) + align_with_view_button.set_custom_minimum_size(Vector2(0, 60)) + align_with_view_button.set_text("Align with view") + _vbox_container.add_child(align_with_view_button) + + var preview_camera_button = Button.new() + preview_camera_button.connect("pressed", _preview_camera.bind(object)) + preview_camera_button.set_custom_minimum_size(Vector2(0, 60)) + preview_camera_button.set_text("Preview Camera") + _vbox_container.add_child(preview_camera_button) + + + +func _align_camera_with_view(object: Object) -> void: + print("Aligning camera with view") + print(object) + +func _preview_camera(object: Object) -> void: + print("Previewing camera") + print(object) diff --git a/godot/addons/phantom_camera/panel/editor.tscn b/godot/addons/phantom_camera/panel/editor.tscn new file mode 100644 index 0000000..0c75c6a --- /dev/null +++ b/godot/addons/phantom_camera/panel/editor.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=4 format=3 uid="uid://cfdoaceoosi1w"] + +[ext_resource type="Script" uid="uid://cgfwg3paxkj2x" path="res://addons/phantom_camera/scripts/panel/editor.gd" id="1_86hp7"] +[ext_resource type="PackedScene" uid="uid://cuqkqsp3ikv5u" path="res://addons/phantom_camera/panel/updater/update_button.tscn" id="1_oowcd"] +[ext_resource type="PackedScene" uid="uid://dbkr3d716wtx0" path="res://addons/phantom_camera/panel/viewfinder/viewfinder_panel.tscn" id="2_xecnk"] + +[node name="EditorPanel" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_86hp7") + +[node name="UpdateButton" parent="." instance=ExtResource("1_oowcd")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 1 + +[node name="ViewfinderPanel" parent="." instance=ExtResource("2_xecnk")] +unique_name_in_owner = true +layout_mode = 2 diff --git a/godot/addons/phantom_camera/panel/updater/download_update_panel.tscn b/godot/addons/phantom_camera/panel/updater/download_update_panel.tscn new file mode 100644 index 0000000..5fa49e3 --- /dev/null +++ b/godot/addons/phantom_camera/panel/updater/download_update_panel.tscn @@ -0,0 +1,253 @@ +[gd_scene load_steps=15 format=3 uid="uid://b25fl4usw0nlp"] + +[ext_resource type="Script" uid="uid://cjblcocen12r3" path="res://addons/phantom_camera/scripts/panel/updater/download_update_panel.gd" id="1_sx5xq"] +[ext_resource type="Texture2D" uid="uid://cc0wmici0eic8" path="res://addons/phantom_camera/icons/phantom_camera_logo.png" id="2_f3yo7"] +[ext_resource type="FontFile" uid="uid://c4mm3of2mc8o5" path="res://addons/phantom_camera/fonts/Nunito-Black.ttf" id="3_h8uk3"] +[ext_resource type="FontFile" uid="uid://dve7mgsjik4dg" path="res://addons/phantom_camera/fonts/Nunito-Regular.ttf" id="4_gwh4i"] +[ext_resource type="Texture2D" uid="uid://censw3w53gldn" path="res://addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png" id="5_bonti"] + +[sub_resource type="ImageTexture" id="ImageTexture_sjwi2"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_insma"] +bg_color = Color(0.0190018, 0.21903, 0.16997, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.0980392, 0.572549, 0.458824, 1) +border_blend = true +corner_radius_bottom_right = 12 +corner_radius_bottom_left = 12 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8m63d"] +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.105882, 0.619608, 0.498039, 1) +corner_radius_bottom_right = 12 +corner_radius_bottom_left = 12 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yn22d"] +bg_color = Color(0.0117647, 0.164706, 0.12549, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.0980392, 0.572549, 0.458824, 1) +border_blend = true +corner_radius_bottom_right = 12 +corner_radius_bottom_left = 12 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_djsbc"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xtrn6"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_o12j0"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_buptb"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_g3tf0"] + +[node name="DownloadUpdatePanel" type="Control"] +custom_minimum_size = Vector2(300, 350) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_bottom = -61.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_sx5xq") + +[node name="DownloadHTTPRequest" type="HTTPRequest" parent="."] +unique_name_in_owner = true + +[node name="Timer" type="Timer" parent="DownloadHTTPRequest"] +one_shot = true + +[node name="VBox" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/separation = 2 + +[node name="VBoxContainer2" type="VBoxContainer" parent="VBox"] +layout_mode = 2 +theme_override_constants/separation = -20 + +[node name="MarginContainer" type="MarginContainer" parent="VBox/VBoxContainer2"] +layout_mode = 2 +theme_override_constants/margin_top = 12 + +[node name="Logo" type="TextureRect" parent="VBox/VBoxContainer2/MarginContainer"] +unique_name_in_owner = true +clip_contents = true +custom_minimum_size = Vector2(300, 160) +layout_mode = 2 +texture = ExtResource("2_f3yo7") +expand_mode = 3 +stretch_mode = 5 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBox/VBoxContainer2"] +layout_mode = 2 +theme_override_constants/separation = -5 + +[node name="NameLabel" type="Label" parent="VBox/VBoxContainer2/VBoxContainer"] +layout_mode = 2 +theme_override_colors/font_color = Color(0.960784, 0.960784, 0.960784, 1) +theme_override_fonts/font = ExtResource("3_h8uk3") +theme_override_font_sizes/font_size = 32 +text = "Phantom Camera" +horizontal_alignment = 1 + +[node name="DownloadVersionLabel" type="Label" parent="VBox/VBoxContainer2/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_colors/font_color = Color(0.960784, 0.960784, 0.960784, 1) +theme_override_fonts/font = ExtResource("4_gwh4i") +theme_override_font_sizes/font_size = 18 +text = "v1.2.3 is available for download." +horizontal_alignment = 1 + +[node name="CurrentVersionLabel" type="Label" parent="VBox"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +theme_override_fonts/font = ExtResource("4_gwh4i") +text = "Current version: 0.0.0" +horizontal_alignment = 1 + +[node name="Center2" type="CenterContainer" parent="VBox"] +layout_mode = 2 + +[node name="NotesButton" type="LinkButton" parent="VBox/Center2"] +layout_mode = 2 +theme_override_colors/font_color = Color(0.917647, 0.631373, 0.368627, 1) +theme_override_colors/font_hover_color = Color(0.721569, 0.454902, 0.192157, 1) +theme_override_fonts/font = ExtResource("3_h8uk3") +theme_override_font_sizes/font_size = 18 +text = "Release Notes" + +[node name="Center" type="CenterContainer" parent="VBox"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBox/Center"] +layout_mode = 2 + +[node name="BreakingLabel" type="Label" parent="VBox/Center/VBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +theme_override_colors/font_color = Color(0.72549, 0.227451, 0.34902, 1) +theme_override_fonts/font = ExtResource("3_h8uk3") +theme_override_font_sizes/font_size = 18 +text = "Potential Breaking Changes +in new release" +horizontal_alignment = 1 +uppercase = true + +[node name="BreakingMarginContainer" type="MarginContainer" parent="VBox/Center/VBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBox/Center/VBoxContainer/BreakingMarginContainer"] +layout_mode = 2 + +[node name="RichTextLabel2" type="RichTextLabel" parent="VBox/Center/VBoxContainer/BreakingMarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_fonts/normal_font = ExtResource("4_gwh4i") +theme_override_fonts/bold_font = ExtResource("3_h8uk3") +theme_override_fonts/mono_font = ExtResource("3_h8uk3") +theme_override_font_sizes/normal_font_size = 18 +theme_override_font_sizes/bold_font_size = 14 +theme_override_font_sizes/mono_font_size = 12 +bbcode_enabled = true +text = "[center][b]I am prepared for any breaking +changes that may occur from this update[/b][/center]" +fit_content = true + +[node name="BreakingOptionButton" type="OptionButton" parent="VBox/Center/VBoxContainer/BreakingMarginContainer/VBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +mouse_default_cursor_shape = 2 +theme_override_fonts/font = ExtResource("3_h8uk3") +theme_override_font_sizes/font_size = 18 +theme_override_icons/arrow = SubResource("ImageTexture_sjwi2") +theme_override_styles/normal = SubResource("StyleBoxFlat_insma") +theme_override_styles/hover = SubResource("StyleBoxFlat_8m63d") +theme_override_styles/pressed = SubResource("StyleBoxFlat_yn22d") +alignment = 1 +item_count = 2 +selected = 0 +popup/item_0/text = "Confirm choice" +popup/item_0/id = 0 +popup/item_1/text = "Yes, I am prepared" +popup/item_1/id = 1 + +[node name="DownloadButton" type="Button" parent="VBox/Center/VBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(240, 90) +layout_mode = 2 +mouse_default_cursor_shape = 2 +theme_override_styles/normal = SubResource("StyleBoxEmpty_djsbc") +theme_override_styles/hover = SubResource("StyleBoxEmpty_xtrn6") +theme_override_styles/pressed = SubResource("StyleBoxEmpty_o12j0") +theme_override_styles/disabled = SubResource("StyleBoxEmpty_buptb") +theme_override_styles/focus = SubResource("StyleBoxEmpty_g3tf0") + +[node name="DownloadButtonBG" type="NinePatchRect" parent="VBox/Center/VBoxContainer/DownloadButton"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("5_bonti") +patch_margin_left = 38 +patch_margin_top = 37 +patch_margin_right = 38 +patch_margin_bottom = 39 + +[node name="UpdateLabel" type="Label" parent="VBox/Center/VBoxContainer/DownloadButton"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 14 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_top = -14.5 +offset_bottom = 14.5 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_colors/font_color = Color(0.960784, 0.960784, 0.960784, 1) +theme_override_colors/font_shadow_color = Color(0, 0, 0, 1) +theme_override_fonts/font = ExtResource("3_h8uk3") +theme_override_font_sizes/font_size = 20 +text = "Update" +horizontal_alignment = 1 +uppercase = true + +[node name="MarginContainer" type="MarginContainer" parent="VBox"] +layout_mode = 2 +theme_override_constants/margin_top = 10 + +[node name="RichTextLabel" type="RichTextLabel" parent="VBox/MarginContainer"] +layout_mode = 2 +theme_override_fonts/normal_font = ExtResource("4_gwh4i") +theme_override_fonts/mono_font = ExtResource("3_h8uk3") +theme_override_font_sizes/normal_font_size = 12 +theme_override_font_sizes/mono_font_size = 12 +bbcode_enabled = true +text = "[center]The updater can be disabled within: +[code]Project Settings / Phantom Camera / Updater / Enable Updater[/code][/center]" +fit_content = true + +[connection signal="pressed" from="VBox/Center2/NotesButton" to="." method="_on_notes_button_pressed"] diff --git a/godot/addons/phantom_camera/panel/updater/update_button.tscn b/godot/addons/phantom_camera/panel/updater/update_button.tscn new file mode 100644 index 0000000..a6efba1 --- /dev/null +++ b/godot/addons/phantom_camera/panel/updater/update_button.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=10 format=3 uid="uid://cuqkqsp3ikv5u"] + +[ext_resource type="FontFile" uid="uid://c4mm3of2mc8o5" path="res://addons/phantom_camera/fonts/Nunito-Black.ttf" id="1_5e5k4"] +[ext_resource type="Script" uid="uid://bwc42i46603qn" path="res://addons/phantom_camera/scripts/panel/updater/update_button.gd" id="1_xtaw5"] +[ext_resource type="Texture2D" uid="uid://d4j4hrb7yusyq" path="res://addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg" id="2_c4d83"] +[ext_resource type="PackedScene" uid="uid://b25fl4usw0nlp" path="res://addons/phantom_camera/panel/updater/download_update_panel.tscn" id="2_vtgcx"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_c7fd1"] +content_margin_left = 10.0 +content_margin_top = 4.0 +content_margin_right = 10.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0980392, 0.415686, 0.341176, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 20 +corner_radius_top_right = 20 +corner_radius_bottom_right = 20 +corner_radius_bottom_left = 20 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_y83dj"] +content_margin_left = 10.0 +content_margin_top = 4.0 +content_margin_right = 10.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.960784, 0.960784, 0.960784, 1) +corner_radius_top_left = 20 +corner_radius_top_right = 20 +corner_radius_bottom_right = 20 +corner_radius_bottom_left = 20 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_slf6e"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_lekqh"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dr4n4"] +content_margin_bottom = 20.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) + +[node name="UpdateButton" type="Button"] +visible = false +offset_left = 1.0 +offset_right = 149.0 +offset_bottom = 28.0 +size_flags_vertical = 3 +theme_override_colors/font_color = Color(0.960784, 0.960784, 0.960784, 1) +theme_override_colors/font_hover_color = Color(0.939288, 0.917743, 0.892615, 1) +theme_override_colors/icon_normal_color = Color(0.960784, 0.960784, 0.960784, 1) +theme_override_fonts/font = ExtResource("1_5e5k4") +theme_override_font_sizes/font_size = 14 +theme_override_styles/normal = SubResource("StyleBoxFlat_c7fd1") +theme_override_styles/hover = SubResource("StyleBoxFlat_y83dj") +theme_override_styles/pressed = SubResource("StyleBoxEmpty_slf6e") +theme_override_styles/focus = SubResource("StyleBoxEmpty_lekqh") +text = "Update available" +icon = ExtResource("2_c4d83") +script = ExtResource("1_xtaw5") + +[node name="HTTPRequest" type="HTTPRequest" parent="."] +unique_name_in_owner = true + +[node name="DownloadDialog" type="AcceptDialog" parent="."] +unique_name_in_owner = true +transparent_bg = true +title = "New Update" +initial_position = 2 +size = Vector2i(450, 480) +transient = false +unresizable = true +borderless = true +keep_title_visible = false +content_scale_mode = 1 +theme_override_constants/buttons_separation = 30 +theme_override_styles/panel = SubResource("StyleBoxFlat_dr4n4") +ok_button_text = "Close" + +[node name="DownloadUpdatePanel" parent="DownloadDialog" instance=ExtResource("2_vtgcx")] +unique_name_in_owner = true +offset_left = 2.0 +offset_top = 2.0 +offset_right = -2.0 +offset_bottom = -80.0 + +[node name="NeedsReloadDialog" type="ConfirmationDialog" parent="."] +unique_name_in_owner = true + +[node name="UpdateFailedDialog" type="AcceptDialog" parent="."] +unique_name_in_owner = true diff --git a/godot/addons/phantom_camera/panel/viewfinder/deadzone_style_box.tres b/godot/addons/phantom_camera/panel/viewfinder/deadzone_style_box.tres new file mode 100644 index 0000000..7353299 --- /dev/null +++ b/godot/addons/phantom_camera/panel/viewfinder/deadzone_style_box.tres @@ -0,0 +1,14 @@ +[gd_resource type="StyleBoxFlat" format=3 uid="uid://dpa7yvxlq043a"] + +[resource] +bg_color = Color(0.227451, 0.72549, 0.603922, 0.2) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_detail = 1 +expand_margin_left = 1.0 +expand_margin_top = 1.0 +expand_margin_right = 1.0 +expand_margin_bottom = 1.0 diff --git a/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list.tscn b/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list.tscn new file mode 100644 index 0000000..332415d --- /dev/null +++ b/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list.tscn @@ -0,0 +1,87 @@ +[gd_scene load_steps=8 format=3 uid="uid://mbjdav5oqves"] + +[ext_resource type="Script" uid="uid://c84cxry3t35ny" path="res://addons/phantom_camera/scripts/panel/viewfinder/host_list.gd" id="1_h6ayt"] +[ext_resource type="Texture2D" uid="uid://5fatldiu7dd5" path="res://addons/phantom_camera/icons/phantom_camera_host.svg" id="1_xlgqb"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_w002y"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kq7gm"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_top = 2 +border_width_right = 2 +border_color = Color(0.960784, 0.960784, 0.960784, 1) +corner_radius_top_right = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ynag5"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.960784, 0.960784, 0.960784, 1) +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_radius_top_right = 6 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q2svd"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_right = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_e0jvt"] +content_margin_left = 0.0 +content_margin_top = 8.0 +content_margin_right = 0.0 +content_margin_bottom = 8.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_top = 2 +border_width_right = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_right = 10 + +[node name="PCamHostList" type="VBoxContainer"] +anchors_preset = 9 +anchor_bottom = 1.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +theme_override_constants/separation = -2 +alignment = 2 +script = ExtResource("1_h6ayt") + +[node name="HostListButton" type="Button" parent="."] +unique_name_in_owner = true +custom_minimum_size = Vector2(40, 40) +layout_mode = 2 +size_flags_horizontal = 0 +theme_override_colors/icon_hover_color = Color(0.0784314, 0.109804, 0.129412, 1) +theme_override_colors/icon_hover_pressed_color = Color(0.0784314, 0.109804, 0.129412, 1) +theme_override_styles/focus = SubResource("StyleBoxEmpty_w002y") +theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_kq7gm") +theme_override_styles/hover = SubResource("StyleBoxFlat_ynag5") +theme_override_styles/pressed = SubResource("StyleBoxFlat_kq7gm") +theme_override_styles/normal = SubResource("StyleBoxFlat_q2svd") +icon = ExtResource("1_xlgqb") +expand_icon = true + +[node name="ScrollContainer" type="ScrollContainer" parent="."] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_e0jvt") +horizontal_scroll_mode = 0 + +[node name="HostListContainer" type="VBoxContainer" parent="ScrollContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_constants/separation = 8 diff --git a/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item.tscn b/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item.tscn new file mode 100644 index 0000000..9ce67e5 --- /dev/null +++ b/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item.tscn @@ -0,0 +1,68 @@ +[gd_scene load_steps=10 format=3 uid="uid://btn6jgv0vix7"] + +[ext_resource type="FontFile" uid="uid://dve7mgsjik4dg" path="res://addons/phantom_camera/fonts/Nunito-Regular.ttf" id="1_anjxo"] +[ext_resource type="Theme" uid="uid://bhppejri5dbsf" path="res://addons/phantom_camera/themes/theme.tres" id="1_wql5t"] +[ext_resource type="Texture2D" uid="uid://rghrkoqrm2ig" path="res://addons/phantom_camera/icons/viewfinder/Select.svg" id="2_71b6g"] +[ext_resource type="ButtonGroup" uid="uid://dfu0b8jbtyr1n" path="res://addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres" id="3_06a0y"] +[ext_resource type="Script" uid="uid://bv24ubx8mutw7" path="res://addons/phantom_camera/scripts/panel/viewfinder/host_list_item.gd" id="3_a5o8b"] +[ext_resource type="Texture2D" uid="uid://cjlv0bg7byjx0" path="res://addons/phantom_camera/icons/warning.svg" id="3_qgpy7"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0rxfi"] +content_margin_right = 6.0 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_llqnh"] + +[sub_resource type="Theme" id="Theme_7h15c"] +Button/colors/icon_hover_color = Color(0.960784, 0.960784, 0.960784, 1) +Button/colors/icon_hover_pressed_color = Color(0.227451, 0.72549, 0.603922, 1) +Button/colors/icon_normal_color = Color(0.227451, 0.72549, 0.603922, 1) +Button/colors/icon_pressed_color = Color(0.227451, 0.72549, 0.603922, 1) +Button/constants/icon_max_width = 20 +Button/styles/focus = SubResource("StyleBoxEmpty_llqnh") + +[node name="HostListItem" type="PanelContainer"] +offset_right = 229.0 +offset_bottom = 34.0 +theme_override_styles/panel = SubResource("StyleBoxEmpty_0rxfi") +script = ExtResource("3_a5o8b") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 2 + +[node name="SelectPCamHost" type="Button" parent="HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 4 +tooltip_text = "Select the Phantom Camera Host node from the scene hierarchy" +focus_mode = 0 +theme = SubResource("Theme_7h15c") +icon = ExtResource("2_71b6g") +flat = true + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 8 + +[node name="ErrorPCamHost" type="TextureRect" parent="HBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(18, 18) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 4 +tooltip_text = "This Phantom Camera Host node will not affect a Camera node. +See the warning in the Scene Tree for more information." +texture = ExtResource("3_qgpy7") +expand_mode = 1 + +[node name="SwitchPCamHost" type="Button" parent="HBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(40, 0) +layout_mode = 2 +tooltip_text = "Change the viewfinder's camera to the camera of this Phantom Camera Host" +theme = ExtResource("1_wql5t") +theme_override_fonts/font = ExtResource("1_anjxo") +theme_override_font_sizes/font_size = 18 +toggle_mode = true +button_group = ExtResource("3_06a0y") +text = "{ PCamHostName }" diff --git a/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres b/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres new file mode 100644 index 0000000..64c4600 --- /dev/null +++ b/godot/addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres @@ -0,0 +1,3 @@ +[gd_resource type="ButtonGroup" format=3 uid="uid://dfu0b8jbtyr1n"] + +[resource] diff --git a/godot/addons/phantom_camera/panel/viewfinder/viewfinder_panel.tscn b/godot/addons/phantom_camera/panel/viewfinder/viewfinder_panel.tscn new file mode 100644 index 0000000..b6caa0d --- /dev/null +++ b/godot/addons/phantom_camera/panel/viewfinder/viewfinder_panel.tscn @@ -0,0 +1,563 @@ +[gd_scene load_steps=28 format=3 uid="uid://dbkr3d716wtx0"] + +[ext_resource type="Script" uid="uid://drmv3363t8amc" path="res://addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd" id="1_utvi8"] +[ext_resource type="StyleBox" uid="uid://dpa7yvxlq043a" path="res://addons/phantom_camera/panel/viewfinder/deadzone_style_box.tres" id="2_uabt4"] +[ext_resource type="FontFile" uid="uid://c4mm3of2mc8o5" path="res://addons/phantom_camera/fonts/Nunito-Black.ttf" id="3_li3i3"] +[ext_resource type="Texture2D" uid="uid://5fatldiu7dd5" path="res://addons/phantom_camera/icons/phantom_camera_host.svg" id="4_lcg1p"] +[ext_resource type="FontFile" uid="uid://dve7mgsjik4dg" path="res://addons/phantom_camera/fonts/Nunito-Regular.ttf" id="5_4jhax"] +[ext_resource type="Texture2D" uid="uid://dy8eifa6aw2en" path="res://addons/phantom_camera/icons/misc/PriorityOverride.svg" id="6_ptuth"] +[ext_resource type="Script" uid="uid://c84cxry3t35ny" path="res://addons/phantom_camera/scripts/panel/viewfinder/host_list.gd" id="7_kpij0"] +[ext_resource type="Theme" uid="uid://bhppejri5dbsf" path="res://addons/phantom_camera/themes/theme.tres" id="8_b4akn"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fle8t"] +bg_color = Color(0.227451, 0.72549, 0.603922, 0.2) +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_detail = 1 +expand_margin_left = 1.0 +expand_margin_top = 1.0 +expand_margin_right = 1.0 +expand_margin_bottom = 1.0 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xmo1t"] +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0.745098, 0.858824, 0.380392, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q7vs4"] +bg_color = Color(0.929412, 0.87451, 0.619608, 1) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color(0, 0, 0, 1) +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_iho1a"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_obaj6"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_4b76l"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yh38y"] +content_margin_left = 10.0 +content_margin_top = 10.0 +content_margin_right = 10.0 +content_margin_bottom = 10.0 +bg_color = Color(0.129412, 0.407843, 0.337255, 1) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color(0.988235, 0.498039, 0.498039, 1) +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gci88"] +content_margin_left = 10.0 +content_margin_top = 10.0 +content_margin_right = 10.0 +content_margin_bottom = 10.0 +bg_color = Color(0.180392, 0.576471, 0.482353, 1) +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fsxik"] +content_margin_left = 10.0 +content_margin_top = 10.0 +content_margin_right = 10.0 +content_margin_bottom = 10.0 +bg_color = Color(0.129412, 0.407843, 0.337255, 1) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_g5wua"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_x4bx8"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_840sd"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ja3vm"] +bg_color = Color(0.53, 0.1643, 0.255725, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_blend = true +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mk273"] +bg_color = Color(0.43, 0.1333, 0.207475, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_blend = true +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_agqdu"] +bg_color = Color(0.72549, 0.227451, 0.34902, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_blend = true +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_w002y"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kq7gm"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_top = 2 +border_width_right = 2 +border_color = Color(0.960784, 0.960784, 0.960784, 1) +corner_radius_top_right = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ynag5"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.960784, 0.960784, 0.960784, 1) +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_radius_top_right = 6 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q2svd"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_right = 8 + +[node name="ViewfinderPanel" type="Control"] +clip_contents = true +custom_minimum_size = Vector2(0, 300) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +mouse_filter = 2 +script = ExtResource("1_utvi8") + +[node name="Viewfinder" type="Control" parent="."] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +metadata/_edit_lock_ = true + +[node name="SubViewportContainer" type="SubViewportContainer" parent="Viewfinder"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +stretch = true + +[node name="SubViewport" type="SubViewport" parent="Viewfinder/SubViewportContainer"] +unique_name_in_owner = true +handle_input_locally = false +canvas_item_default_texture_filter = 0 +gui_disable_input = true +size = Vector2i(1152, 648) +size_2d_override_stretch = true +render_target_update_mode = 4 + +[node name="Camera2D" type="Camera2D" parent="Viewfinder/SubViewportContainer/SubViewport"] +unique_name_in_owner = true +editor_draw_screen = false + +[node name="DeadZoneHBoxContainer" type="HBoxContainer" parent="Viewfinder"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_constants/separation = 0 + +[node name="DeadZoneLeftHBoxContainer" type="VBoxContainer" parent="Viewfinder/DeadZoneHBoxContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 +theme_override_constants/separation = 0 + +[node name="DeadZoneLeftTopPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneLeftHBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneLeftCenterPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneLeftHBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneLeftBottomPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneLeftHBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneCenterHBoxContainer" type="VBoxContainer" parent="Viewfinder/DeadZoneHBoxContainer"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 4 +mouse_filter = 2 +theme_override_constants/separation = 0 + +[node name="DeadZoneCenterTopPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneCenterHBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneCenterCenterPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneCenterHBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 4 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_fle8t") + +[node name="DeadZoneCenterBottomPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneCenterHBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneRightHBoxContainer" type="VBoxContainer" parent="Viewfinder/DeadZoneHBoxContainer"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 +theme_override_constants/separation = 0 + +[node name="DeadZoneRightTopPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneRightHBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneRightCenterPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneRightHBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="DeadZoneRightBottomPanel" type="Panel" parent="Viewfinder/DeadZoneHBoxContainer/DeadZoneRightHBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +theme_override_styles/panel = ExtResource("2_uabt4") + +[node name="AspectRatioContainer" type="AspectRatioContainer" parent="Viewfinder"] +unique_name_in_owner = true +clip_contents = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +ratio = 1.77778 + +[node name="CameraViewportPanel" type="Panel" parent="Viewfinder/AspectRatioContainer"] +layout_mode = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_xmo1t") + +[node name="TargetPoint" type="Panel" parent="Viewfinder/AspectRatioContainer/CameraViewportPanel"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -3.0 +offset_top = -3.0 +offset_right = 3.0 +offset_bottom = 3.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_q7vs4") + +[node name="NoSupportMsg" type="Label" parent="."] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = -8.0 +offset_bottom = -8.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_fonts/font = ExtResource("3_li3i3") +theme_override_font_sizes/font_size = 24 +theme_override_styles/normal = SubResource("StyleBoxEmpty_iho1a") +text = "Control scenes are not supported" +horizontal_alignment = 1 +vertical_alignment = 1 +metadata/_edit_lock_ = true + +[node name="EmptyStateControl" type="Control" parent="."] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +metadata/_edit_use_anchors_ = true +metadata/_edit_lock_ = true + +[node name="BGColorRect" type="ColorRect" parent="EmptyStateControl"] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 1) +metadata/_edit_lock_ = true + +[node name="VBoxContainer" type="VBoxContainer" parent="EmptyStateControl"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -200.0 +offset_top = -112.0 +offset_right = 200.0 +offset_bottom = 112.0 +grow_horizontal = 2 +grow_vertical = 2 +alignment = 1 + +[node name="EmptyStateIcon" type="TextureRect" parent="EmptyStateControl/VBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 64) +layout_mode = 2 +texture = ExtResource("4_lcg1p") +expand_mode = 1 +stretch_mode = 5 + +[node name="EmptyStateText" type="RichTextLabel" parent="EmptyStateControl/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_colors/default_color = Color(1, 1, 1, 1) +theme_override_fonts/normal_font = ExtResource("5_4jhax") +theme_override_fonts/bold_font = ExtResource("3_li3i3") +theme_override_font_sizes/normal_font_size = 24 +theme_override_font_sizes/bold_font_size = 24 +theme_override_styles/focus = SubResource("StyleBoxEmpty_obaj6") +theme_override_styles/normal = SubResource("StyleBoxEmpty_iho1a") +bbcode_enabled = true +text = "[center][b]NodeType[/b] Description [/center]" +fit_content = true + +[node name="AddNodeButton" type="Button" parent="EmptyStateControl/VBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(400, 54) +layout_mode = 2 +size_flags_horizontal = 4 +focus_mode = 0 +theme_override_colors/font_color = Color(1, 1, 1, 1) +theme_override_fonts/font = ExtResource("3_li3i3") +theme_override_font_sizes/font_size = 24 +theme_override_styles/focus = SubResource("StyleBoxEmpty_4b76l") +theme_override_styles/hover = SubResource("StyleBoxFlat_yh38y") +theme_override_styles/pressed = SubResource("StyleBoxFlat_gci88") +theme_override_styles/normal = SubResource("StyleBoxFlat_fsxik") + +[node name="AddNodeTypeText" type="RichTextLabel" parent="EmptyStateControl/VBoxContainer/AddNodeButton"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 9.0 +offset_bottom = -11.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_colors/default_color = Color(1, 1, 1, 1) +theme_override_fonts/normal_font = ExtResource("5_4jhax") +theme_override_fonts/bold_font = ExtResource("3_li3i3") +theme_override_font_sizes/normal_font_size = 24 +theme_override_font_sizes/bold_font_size = 24 +theme_override_styles/focus = SubResource("StyleBoxEmpty_g5wua") +theme_override_styles/normal = SubResource("StyleBoxEmpty_x4bx8") +bbcode_enabled = true +text = "[center]Add [img=32]res://addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg[/img] [b]{NodeType}[/b][/center]" +scroll_active = false + +[node name="PriorityOverrideButton" type="Button" parent="."] +unique_name_in_owner = true +visible = false +layout_mode = 1 +offset_left = 5.0 +offset_top = 5.0 +offset_right = 165.0 +offset_bottom = 57.0 +mouse_default_cursor_shape = 2 +theme_override_styles/focus = SubResource("StyleBoxEmpty_840sd") +theme_override_styles/hover = SubResource("StyleBoxFlat_ja3vm") +theme_override_styles/pressed = SubResource("StyleBoxFlat_mk273") +theme_override_styles/normal = SubResource("StyleBoxFlat_agqdu") +metadata/_edit_lock_ = true + +[node name="PriorityOverrideIcon" type="TextureRect" parent="PriorityOverrideButton"] +layout_mode = 1 +offset_left = 8.0 +offset_top = 4.0 +offset_right = 32.0 +offset_bottom = 28.0 +texture = ExtResource("6_ptuth") +expand_mode = 1 + +[node name="PriorityOverrideByLabel" type="Label" parent="PriorityOverrideButton"] +layout_mode = 0 +offset_left = 30.0 +offset_top = 1.0 +offset_right = 140.0 +offset_bottom = 24.0 +theme_override_fonts/font = ExtResource("3_li3i3") +theme_override_font_sizes/font_size = 14 +text = "OVERRIDDEN BY" +vertical_alignment = 1 + +[node name="PriorityOverrideNameLabel" type="Label" parent="PriorityOverrideButton"] +unique_name_in_owner = true +layout_mode = 0 +offset_left = 6.0 +offset_top = 21.0 +offset_right = 153.0 +offset_bottom = 44.0 +theme_override_fonts/font = ExtResource("5_4jhax") +theme_override_font_sizes/font_size = 14 +text = "PCam_Name +" +vertical_alignment = 1 +text_overrun_behavior = 3 + +[node name="SizeLabel" type="Label" parent="."] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 4 +anchor_top = 0.5 +anchor_bottom = 0.5 +offset_top = -11.5 +offset_right = 40.0 +offset_bottom = 11.5 +grow_vertical = 2 + +[node name="PCamHostList" type="VBoxContainer" parent="."] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = -1 +anchor_bottom = 1.0 +offset_top = 588.0 +grow_vertical = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +theme_override_constants/separation = -2 +alignment = 2 +script = ExtResource("7_kpij0") + +[node name="HostListButton" type="Button" parent="PCamHostList"] +unique_name_in_owner = true +custom_minimum_size = Vector2(40, 40) +layout_mode = 2 +size_flags_horizontal = 0 +theme_override_colors/icon_hover_pressed_color = Color(0.0784314, 0.109804, 0.129412, 1) +theme_override_colors/icon_hover_color = Color(0.0784314, 0.109804, 0.129412, 1) +theme_override_styles/focus = SubResource("StyleBoxEmpty_w002y") +theme_override_styles/hover_pressed = SubResource("StyleBoxFlat_kq7gm") +theme_override_styles/hover = SubResource("StyleBoxFlat_ynag5") +theme_override_styles/pressed = SubResource("StyleBoxFlat_kq7gm") +theme_override_styles/normal = SubResource("StyleBoxFlat_q2svd") +icon = ExtResource("4_lcg1p") +expand_icon = true + +[node name="PanelContainer" type="PanelContainer" parent="PCamHostList"] +layout_mode = 2 +size_flags_vertical = 3 +theme = ExtResource("8_b4akn") + +[node name="ScrollContainer" type="ScrollContainer" parent="PCamHostList/PanelContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +theme = ExtResource("8_b4akn") +horizontal_scroll_mode = 0 + +[node name="HostListContainer" type="VBoxContainer" parent="PCamHostList/PanelContainer/ScrollContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme = ExtResource("8_b4akn") diff --git a/godot/addons/phantom_camera/plugin.cfg b/godot/addons/phantom_camera/plugin.cfg new file mode 100644 index 0000000..012efa6 --- /dev/null +++ b/godot/addons/phantom_camera/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Phantom Camera" +description="Control the movement and dynamically tween 2D & 3D cameras positions. Built for Godot 4. Inspired by Cinemachine." +author="Marcus Skov" +version="0.9.2" +script="plugin.gd" diff --git a/godot/addons/phantom_camera/plugin.gd b/godot/addons/phantom_camera/plugin.gd new file mode 100644 index 0000000..0421330 --- /dev/null +++ b/godot/addons/phantom_camera/plugin.gd @@ -0,0 +1,181 @@ +@tool +extends EditorPlugin + +#region Constants + +const PCAM_HOST: String = "PhantomCameraHost" +const PCAM_2D: String = "PhantomCamera2D" +const PCAM_3D: String = "PhantomCamera3D" +const PCAM_NOISE_EMITTER_2D: String = "PhantomCameraNoiseEmitter2D" +const PCAM_NOISE_EMITTER_3D: String = "PhantomCameraNoiseEmitter3D" + +const PCam3DPlugin: Script = preload("res://addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo_plugin.gd") +const PCam3DNoiseEmitterPlugin: Script = preload("res://addons/phantom_camera/scripts/gizmos/phantom_camera_noise_emitter_gizmo_plugin_3d.gd") +const EditorPanel: PackedScene = preload("res://addons/phantom_camera/panel/editor.tscn") +const updater_constants: Script = preload("res://addons/phantom_camera/scripts/panel/updater/updater_constants.gd") +const PHANTOM_CAMERA_MANAGER: StringName = "PhantomCameraManager" + +#endregion + +#region Private Variables + +var _settings_show_jitter_tips: String = "phantom_camera/tips/show_jitter_tips" +var _settings_enable_editor_shortcut: String = "phantom_camera/general/enable_editor_shortcut" +var _settings_editor_shortcut: String = "phantom_camera/general/editor_shortcut" + +# TODO - Pending merge of https://github.com/godotengine/godot/pull/102889 - Should only support Godot version after the release that is featured in +#var _editor_shortcut: Shortcut = Shortcut.new() +#var _editor_shortcut_input: InputEventKey +#endregion + +#region Public Variables + +var pcam_3d_gizmo_plugin = PCam3DPlugin.new() +var pcam_3d_noise_emitter_gizmo_plugin = PCam3DNoiseEmitterPlugin.new() + +var editor_panel_instance: Control +var panel_button: Button +#var viewfinder_panel_instance + + +#endregion + +#region Private Functions + +func _enable_plugin() -> void: + print_rich("Phantom Camera documentation can be found at: [url=https://phantom-camera.dev]https://phantom-camera.dev[/url]") + if not Engine.has_singleton(PHANTOM_CAMERA_MANAGER): + add_autoload_singleton(PHANTOM_CAMERA_MANAGER, "res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd") + + +func _disable_plugin() -> void: + remove_autoload_singleton(PHANTOM_CAMERA_MANAGER) + + +func _enter_tree() -> void: + add_autoload_singleton(PHANTOM_CAMERA_MANAGER, "res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd") + + # Phantom Camera Nodes + add_custom_type(PCAM_2D, "Node2D", preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd"), preload("res://addons/phantom_camera/icons/phantom_camera_2d.svg")) + add_custom_type(PCAM_3D, "Node3D", preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd"), preload("res://addons/phantom_camera/icons/phantom_camera_2d.svg")) + add_custom_type(PCAM_HOST, "Node", preload("res://addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd"), preload("res://addons/phantom_camera/icons/phantom_camera_2d.svg")) + add_custom_type(PCAM_NOISE_EMITTER_2D, "Node2D", preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_2d.gd"), preload("res://addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg")) + add_custom_type(PCAM_NOISE_EMITTER_3D, "Node3D", preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_3d.gd"), preload("res://addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg")) + + # Phantom Camera 3D Gizmo + add_node_3d_gizmo_plugin(pcam_3d_gizmo_plugin) + add_node_3d_gizmo_plugin(pcam_3d_noise_emitter_gizmo_plugin) + + var setting_updater_mode: String + var setting_updater_mode_default: int + if FileAccess.file_exists("res://dev_scenes/3d/dev_scene_3d.tscn"): # For forks + setting_updater_mode = "Off, Console Output" + setting_updater_mode_default = 1 + else: # For end-users + setting_updater_mode = "Off, Console Output, Updater Window" + setting_updater_mode_default = 2 + + if not ProjectSettings.has_setting(updater_constants.setting_updater_mode): + ProjectSettings.set_setting(updater_constants.setting_updater_mode, setting_updater_mode_default) + ProjectSettings.add_property_info({ + "name": updater_constants.setting_updater_mode, + "type": TYPE_INT, + "hint": PROPERTY_HINT_ENUM, + "hint_string": setting_updater_mode, + }) + ProjectSettings.set_initial_value(updater_constants.setting_updater_mode, setting_updater_mode_default) + ProjectSettings.set_as_basic(updater_constants.setting_updater_mode, true) + + + ## Setting for enabling / disabling Jitter tips in the Output + if not ProjectSettings.has_setting(_settings_show_jitter_tips): + ProjectSettings.set_setting(_settings_show_jitter_tips, true) + ProjectSettings.add_property_info({ + "name": _settings_show_jitter_tips, + "type": TYPE_BOOL, + }) + ProjectSettings.set_initial_value(_settings_show_jitter_tips, true) + ProjectSettings.set_as_basic(_settings_show_jitter_tips, true) + + +# TODO - Pending merge of https://github.com/godotengine/godot/pull/102889 - Should only support Godot version after this release +# if not ProjectSettings.has_setting(_settings_enable_editor_shortcut): +# ProjectSettings.set_setting(_settings_enable_editor_shortcut, false) +# ProjectSettings.set_initial_value(_settings_enable_editor_shortcut, false) + +# TODO - Pending merge of https://github.com/godotengine/godot/pull/102889 - Should only support Godot version after this release +# _viewfinder_shortcut_default.events = [editor_shortcut] +# if ProjectSettings.get_setting(_settings_enable_editor_shortcut): +# if not ProjectSettings.has_setting(_settings_editor_shortcut): +# ProjectSettings.set_setting(_settings_editor_shortcut, _editor_shortcut) +# ProjectSettings.set_initial_value(_settings_editor_shortcut, _editor_shortcut) + + + # TODO - Should be disabled unless in editor + # Viewfinder + editor_panel_instance = EditorPanel.instantiate() + editor_panel_instance.editor_plugin = self + panel_button = add_control_to_bottom_panel(editor_panel_instance, "Phantom Camera") + panel_button.toggled.connect(_btn_toggled) + if panel_button.toggle_mode: _btn_toggled(true) + + scene_changed.connect(editor_panel_instance.viewfinder.scene_changed) + scene_changed.connect(_scene_changed) + + +func _exit_tree() -> void: + panel_button.toggled.disconnect(_btn_toggled) + scene_changed.disconnect(editor_panel_instance.viewfinder.scene_changed) + scene_changed.disconnect(_scene_changed) + + remove_control_from_bottom_panel(editor_panel_instance) + editor_panel_instance.queue_free() + + remove_node_3d_gizmo_plugin(pcam_3d_gizmo_plugin) + remove_node_3d_gizmo_plugin(pcam_3d_noise_emitter_gizmo_plugin) + + remove_custom_type(PCAM_2D) + remove_custom_type(PCAM_3D) + remove_custom_type(PCAM_HOST) + remove_custom_type(PCAM_NOISE_EMITTER_2D) + remove_custom_type(PCAM_NOISE_EMITTER_3D) + + remove_autoload_singleton(PHANTOM_CAMERA_MANAGER) +# if get_tree().root.get_node_or_null(String(PHANTOM_CAMERA_MANAGER)): +# remove_autoload_singleton(PHANTOM_CAMERA_MANAGER) + + +func _btn_toggled(toggled_on: bool): + editor_panel_instance.viewfinder.set_visibility(toggled_on) +# if toggled_on: +# editor_panel_instance.viewfinder.viewfinder_visible = true +# editor_panel_instance.viewfinder.visibility_check() +# else: +# editor_panel_instance.viewfinder.viewfinder_visible = false + +func _make_visible(visible): + if editor_panel_instance: + editor_panel_instance.set_visible(visible) + +## TODO - Signal can be added directly to the editor_panel with the changes in Godot 4.5 (https://github.com/godotengine/godot/pull/102986) +func _scene_changed(scene_root: Node) -> void: + editor_panel_instance.viewfinder.scene_changed(scene_root) + +# TODO - Pending merge of https://github.com/godotengine/godot/pull/102889 - Should only support Godot version after this release +#func _set_editor_shortcut() -> InputEventKey: +# var shortcut: InputEventKey = InputEventKey.new() +# shortcut.keycode = 67 # Key = C +# shortcut.alt_pressed = true +# return shortcut + +#endregion + + +#region Public Functions + +func get_version() -> String: + var config: ConfigFile = ConfigFile.new() + config.load(get_script().resource_path.get_base_dir() + "/plugin.cfg") + return config.get_value("plugin", "version") + +#endregion diff --git a/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo.gd b/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo.gd new file mode 100644 index 0000000..27e7eed --- /dev/null +++ b/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo.gd @@ -0,0 +1,84 @@ +@tool +extends EditorNode3DGizmo + +#var pcam_3d: PhantomCamera3D + +func _redraw() -> void: + clear() + + var icon: Material = get_plugin().get_material(get_plugin().get_name(), self) + add_unscaled_billboard(icon, 0.035) + + var pcam_3d: PhantomCamera3D = get_node_3d() + +# if pcam_3d.is_following(): +# _draw_target(pcam_3d, pcam_3d.get_follow_target_position(), "follow_target") +# if pcam_3d.is_looking_at(): +# _draw_target(pcam_3d, pcam_3d.get_look_at_target_position(), "look_at_target") + + if pcam_3d.is_active(): return + + var frustum_lines: PackedVector3Array = PackedVector3Array() + var height: float = 0.25 + var width: float = height * 1.25 + var forward: float = height * -1.5 + + # Trapezoid + frustum_lines.push_back(Vector3.ZERO) + frustum_lines.push_back(Vector3(-width, height, forward)) + + frustum_lines.push_back(Vector3.ZERO) + frustum_lines.push_back(Vector3(width, height, forward)) + + frustum_lines.push_back(Vector3.ZERO) + frustum_lines.push_back(Vector3(-width, -height, forward)) + + frustum_lines.push_back(Vector3.ZERO) + frustum_lines.push_back(Vector3(width, -height, forward)) + + ####### + # Frame + ####### + ## Left + frustum_lines.push_back(Vector3(-width, height, forward)) + frustum_lines.push_back(Vector3(-width, -height, forward)) + + ## Bottom + frustum_lines.push_back(Vector3(-width, -height, forward)) + frustum_lines.push_back(Vector3(width, -height, forward)) + + ## Right + frustum_lines.push_back(Vector3(width, -height, forward)) + frustum_lines.push_back(Vector3(width, height, forward)) + + ## Top + frustum_lines.push_back(Vector3(width, height, forward)) + frustum_lines.push_back(Vector3(-width, height, forward)) + + ############## + # Up Direction + ############## + var up_height: float = height + 0.15 + var up_width: float = width / 3 + + ## Left + frustum_lines.push_back(Vector3(0, up_height, forward)) + frustum_lines.push_back(Vector3(-up_width, height, forward)) + + ## Right + frustum_lines.push_back(Vector3(0, up_height, forward)) + frustum_lines.push_back(Vector3(up_width, height, forward)) + + var frustum_material: StandardMaterial3D = get_plugin().get_material("frustum", self) + add_lines(frustum_lines, frustum_material, false) + + +func _draw_target(pcam_3d: Node3D, target_position: Vector3, type: String) -> void: + var target_lines: PackedVector3Array = PackedVector3Array() + var direction: Vector3 = target_position - pcam_3d.global_position + var end_position: Vector3 = pcam_3d.global_basis.z * direction + + target_lines.push_back(Vector3.ZERO) + target_lines.push_back(end_position) + var target_material: StandardMaterial3D = get_plugin().get_material(type, self) + add_lines(target_lines, target_material, false) diff --git a/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo_plugin.gd b/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo_plugin.gd new file mode 100644 index 0000000..2caf713 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo_plugin.gd @@ -0,0 +1,37 @@ +@tool +extends EditorNode3DGizmoPlugin + +const PhantomCamera3DNode: Script = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd") +const PhantomCamera3DGizmo: Script = preload("res://addons/phantom_camera/scripts/gizmos/phantom_camera_3d_gizmo.gd") +const _icon_texture: Texture2D = preload("res://addons/phantom_camera/icons/phantom_camera_gizmo.svg") +var _gizmo_name: String = "PhantomCamera3D" + +var gizmo_name: String: set = set_gizmo_name +var _gizmo_icon: Texture2D +var _gizmo_spatial_script: Script = PhantomCamera3DNode + + +func set_gizmo_name(name: String) -> void: + _gizmo_name = name + + +func _get_gizmo_name() -> String: + return _gizmo_name + + +func _has_gizmo(spatial: Node3D) -> bool: + return spatial is PhantomCamera3D + + +func _init() -> void: + create_icon_material(gizmo_name, _icon_texture, false, Color.WHITE) + create_material("frustum", Color8(252, 127, 127, 255)) + create_material("follow_target", Color8(185, 58, 89)) + create_material("look_at_target", Color8(61, 207, 225)) + + +func _create_gizmo(for_node_3d: Node3D) -> EditorNode3DGizmo: + if for_node_3d is PhantomCamera3DNode: + return PhantomCamera3DGizmo.new() + else: + return null diff --git a/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_noise_emitter_gizmo_plugin_3d.gd b/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_noise_emitter_gizmo_plugin_3d.gd new file mode 100644 index 0000000..3dd4d3e --- /dev/null +++ b/godot/addons/phantom_camera/scripts/gizmos/phantom_camera_noise_emitter_gizmo_plugin_3d.gd @@ -0,0 +1,29 @@ +extends EditorNode3DGizmoPlugin + +var _spatial_script: Script = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_3d.gd") +var _gizmo_icon: Texture2D = preload("res://addons/phantom_camera/icons/phantom_camera_noise_emitter_gizmo.svg") + +var _gizmo_name: StringName = "PhantomCameraNoiseEmitter" + +func _init() -> void: + create_material("main", Color8(252, 127, 127, 255)) + create_handle_material("handles") + create_icon_material(_gizmo_name, _gizmo_icon, false, Color.WHITE) + + +func _has_gizmo(node: Node3D): + return node.get_script() == _spatial_script + + +func _get_gizmo_name() -> String: + return _gizmo_name + + +func _redraw(gizmo: EditorNode3DGizmo): + gizmo.clear() + + var icon: Material = get_material(_gizmo_name, gizmo) + gizmo.add_unscaled_billboard(icon, 0.035) + + #var material = get_material("main", gizmo) + #gizmo.add_lines(_draw_frustum(), material) diff --git a/godot/addons/phantom_camera/scripts/managers/PhantomCameraManager.cs b/godot/addons/phantom_camera/scripts/managers/PhantomCameraManager.cs new file mode 100644 index 0000000..5005230 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/managers/PhantomCameraManager.cs @@ -0,0 +1,36 @@ +using System.Linq; +using Godot; + +#nullable enable + +namespace PhantomCamera.Manager; + +public static class PhantomCameraManager +{ + private static GodotObject? _instance; + + public static GodotObject Instance => _instance ??= Engine.GetSingleton("PhantomCameraManager"); + + public static PhantomCamera2D[] PhantomCamera2Ds => + Instance.Call(MethodName.GetPhantomCamera2Ds).AsGodotArray() + .Select(node => new PhantomCamera2D(node)).ToArray(); + + public static PhantomCamera3D[] PhantomCamera3Ds => + Instance.Call(MethodName.GetPhantomCamera3Ds).AsGodotArray() + .Select(node => new PhantomCamera3D(node)).ToArray(); + + public static PhantomCameraHost[] PhantomCameraHosts => + Instance.Call(MethodName.GetPhantomCameraHosts).AsGodotArray() + .Select(node => new PhantomCameraHost(node)).ToArray(); + + public static PhantomCamera2D[] GetPhantomCamera2Ds() => PhantomCamera2Ds; + public static PhantomCamera3D[] GetPhantomCamera3Ds() => PhantomCamera3Ds; + public static PhantomCameraHost[] GetPhantomCameraHosts() => PhantomCameraHosts; + + public static class MethodName + { + public const string GetPhantomCamera2Ds = "get_phantom_camera_2ds"; + public const string GetPhantomCamera3Ds = "get_phantom_camera_3ds"; + public const string GetPhantomCameraHosts = "get_phantom_camera_hosts"; + } +} diff --git a/godot/addons/phantom_camera/scripts/managers/phantom_camera_manager.gd b/godot/addons/phantom_camera/scripts/managers/phantom_camera_manager.gd new file mode 100644 index 0000000..6e13d9a --- /dev/null +++ b/godot/addons/phantom_camera/scripts/managers/phantom_camera_manager.gd @@ -0,0 +1,149 @@ +@tool +extends Node + +const _CONSTANTS = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +#region Signals + +# Noise +signal noise_2d_emitted(noise_output: Transform2D, emitter_layer: int) +signal noise_3d_emitted(noise_output: Transform3D, emitter_layer: int) + +# PCam Host +signal pcam_host_added_to_scene(pcam_host: PhantomCameraHost) +signal pcam_host_removed_from_scene(pcam_host: PhantomCameraHost) + +# PCam +signal pcam_added_to_scene(pcam: Node) +signal pcam_removed_from_scene(pcam: Node) + +# Priority +signal pcam_priority_changed(pcam: Node) +signal pcam_visibility_changed(pcam: Node) + +signal pcam_teleport(pcam: Node) + +# Limit (2D) +signal limit_2d_changed(side: int, limit: int) +signal draw_limit_2d(enabled: bool) + +# Camera3DResource (3D) +signal camera_3d_resource_changed(property: String, value: Variant) + +# Viewfinder Signals +signal viewfinder_pcam_host_switch(pcam_host: PhantomCameraHost) +signal pcam_priority_override(pcam: Node, shouldOverride: bool) +signal pcam_dead_zone_changed(pcam: Node) +signal pcam_host_layer_changed(pcam: Node) + +#endregion + +#region Private Variables + +var _phantom_camera_host_list: Array[PhantomCameraHost] +var _phantom_camera_2d_list: Array[PhantomCamera2D] +var _phantom_camera_3d_list: Array[Node] ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + +#endregion + +#region Public Variables + +var phantom_camera_hosts: Array[PhantomCameraHost]: + get: + return _phantom_camera_host_list + +var phantom_camera_2ds: Array[PhantomCamera2D]: + get: + return _phantom_camera_2d_list + +var phantom_camera_3ds: Array[Node]: ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + get: + return _phantom_camera_3d_list + +var screen_size: Vector2i + +#endregion + +#region Private Functions + +func _enter_tree() -> void: + if not Engine.has_singleton(_CONSTANTS.PCAM_MANAGER_NODE_NAME): + Engine.register_singleton(_CONSTANTS.PCAM_MANAGER_NODE_NAME, self) + Engine.physics_jitter_fix = 0 + + +func _ready() -> void: + # Setting default screensize + screen_size = Vector2i( + ProjectSettings.get_setting("display/window/size/viewport_width"), + ProjectSettings.get_setting("display/window/size/viewport_height") + ) + + # For editor + if Engine.is_editor_hint(): + ProjectSettings.settings_changed.connect(func(): + screen_size = Vector2i( + ProjectSettings.get_setting("display/window/size/viewport_width"), + ProjectSettings.get_setting("display/window/size/viewport_height") + ) + ) + # For runtime + else: + get_tree().get_root().size_changed.connect(func(): + screen_size = get_viewport().get_visible_rect().size + ) + +#endregion + +#region Public Functions + +func pcam_host_added(caller: Node) -> void: + if is_instance_of(caller, PhantomCameraHost): + _phantom_camera_host_list.append(caller) + pcam_host_added_to_scene.emit(caller) + else: + printerr("This method can only be called from a PhantomCameraHost node") + +func pcam_host_removed(caller: Node) -> void: + if is_instance_of(caller, PhantomCameraHost): + _phantom_camera_host_list.erase(caller) + pcam_host_removed_from_scene.emit(caller) + else: + printerr("This method can only be called from a PhantomCameraHost node") + + +func pcam_added(caller) -> void: + if is_instance_of(caller, PhantomCamera2D): + _phantom_camera_2d_list.append(caller) + pcam_added_to_scene.emit(caller) + elif caller.is_class("PhantomCamera3D"): ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + _phantom_camera_3d_list.append(caller) + pcam_added_to_scene.emit(caller) + +func pcam_removed(caller) -> void: + if is_instance_of(caller, PhantomCamera2D): + _phantom_camera_2d_list.erase(caller) + pcam_removed_from_scene.emit(caller) + elif caller.is_class("PhantomCamera3D"): ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + _phantom_camera_3d_list.erase(caller) + pcam_removed_from_scene.emit(caller) + else: + printerr("This method can only be called from a PhantomCamera node") + + +func get_phantom_camera_hosts() -> Array[PhantomCameraHost]: + return _phantom_camera_host_list + +func get_phantom_camera_2ds() -> Array[PhantomCamera2D]: + return _phantom_camera_2d_list + +func get_phantom_camera_3ds() -> Array: ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + return _phantom_camera_3d_list + + +func scene_changed() -> void: + _phantom_camera_2d_list.clear() + _phantom_camera_3d_list.clear() + _phantom_camera_host_list.clear() + +#endregion diff --git a/godot/addons/phantom_camera/scripts/panel/editor.gd b/godot/addons/phantom_camera/scripts/panel/editor.gd new file mode 100644 index 0000000..a10018c --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/editor.gd @@ -0,0 +1,23 @@ +@tool +extends VBoxContainer + +#region Onready + +@onready var updater: Control = %UpdateButton +@onready var viewfinder: Control = %ViewfinderPanel + +#endregion + +#region Public Variables + +var editor_plugin: EditorPlugin + +#endregion + + +#region Private Functions + +func _ready(): + updater.editor_plugin = editor_plugin + +#endregion diff --git a/godot/addons/phantom_camera/scripts/panel/updater/download_update_panel.gd b/godot/addons/phantom_camera/scripts/panel/updater/download_update_panel.gd new file mode 100644 index 0000000..b19beb9 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/updater/download_update_panel.gd @@ -0,0 +1,162 @@ +####################################################################### +# Credit goes to the Dialogue Manager plugin for this script +# Check it out at: https://github.com/nathanhoad/godot_dialogue_manager +####################################################################### + +@tool +extends Control + +#region Constants + +const TEMP_FILE_NAME = "user://temp.zip" + +#endregion + + +#region Signals + +signal failed() +signal updated(updated_to_version: String) + +#endregion + + +#region @onready + +#@onready var logo: TextureRect = %Logo +@onready var _download_verion: Label = %DownloadVersionLabel +@onready var _download_http_request: HTTPRequest = %DownloadHTTPRequest +@onready var _download_button: Button = %DownloadButton +@onready var _download_button_bg: NinePatchRect = %DownloadButtonBG +@onready var _download_label: Label = %UpdateLabel + +@onready var _breaking_label: Label = %BreakingLabel +@onready var _breaking_margin_container: MarginContainer = %BreakingMarginContainer +@onready var _breaking_options_button: OptionButton = %BreakingOptionButton +#@onready var current_version_label: Label = %CurrentVersionLabel + +#endregion + + +#region Variables + +# Todo - For 4.2 upgrade - Shows current version +var _download_dialogue: AcceptDialog +var _button_texture_default: Texture2D = load("res://addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png") +var _button_texture_hover: Texture2D = load("res://addons/phantom_camera/assets/PhantomCameraBtnPrimaryHover.png") + +var next_version_release: Dictionary: + set(value): + next_version_release = value + _download_verion.text = "%s update is available for download" % value.tag_name.substr(1) + # Todo - For 4.2 upgrade + #current_version_label.text = "Current version is " + editor_plugin.get_version() + get: + return next_version_release + +var _breaking_window_height: float = 520 +var _breaking_window_height_update: float = 600 + +#endregion + + +#region Private Functions + +func _ready() -> void: + _download_http_request.request_completed.connect(_on_http_request_request_completed) + _download_button.pressed.connect(_on_download_button_pressed) + _download_button.mouse_entered.connect(_on_mouse_entered) + _download_button.mouse_exited.connect(_on_mouse_exited) + + _breaking_label.hide() + _breaking_margin_container.hide() + _breaking_options_button.hide() + + _breaking_options_button.item_selected.connect(_on_item_selected) + + +func _on_item_selected(index: int) -> void: + if index == 1: + _download_button.show() + _download_dialogue.size = Vector2(_download_dialogue.size.x, _breaking_window_height_update) + else: + _download_button.hide() + _download_dialogue.size = Vector2(_download_dialogue.size.x, _breaking_window_height) + + +func _on_download_button_pressed() -> void: + _download_http_request.request(next_version_release.zipball_url) + _download_button.disabled = true + _download_label.text = "Downloading..." + _download_button_bg.hide() + + +func _on_mouse_entered() -> void: + _download_button_bg.set_texture(_button_texture_hover) + + +func _on_mouse_exited() -> void: + _download_button_bg.set_texture(_button_texture_default) + + +func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: + if result != HTTPRequest.RESULT_SUCCESS: + failed.emit() + return + + # Save the downloaded zip + var zip_file: FileAccess = FileAccess.open(TEMP_FILE_NAME, FileAccess.WRITE) + zip_file.store_buffer(body) + zip_file.close() + + OS.move_to_trash(ProjectSettings.globalize_path("res://addons/phantom_camera")) + + var zip_reader: ZIPReader = ZIPReader.new() + zip_reader.open(TEMP_FILE_NAME) + var files: PackedStringArray = zip_reader.get_files() + + var base_path = files[1] + # Remove archive folder + files.remove_at(0) + # Remove assets folder + files.remove_at(0) + + for path in files: + var new_file_path: String = path.replace(base_path, "") + if path.ends_with("/"): + DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path) + else: + var file: FileAccess = FileAccess.open("res://addons/%s" % new_file_path, FileAccess.WRITE) + file.store_buffer(zip_reader.read_file(path)) + + zip_reader.close() + DirAccess.remove_absolute(TEMP_FILE_NAME) + + updated.emit(next_version_release.tag_name.substr(1)) + + +func _on_notes_button_pressed() -> void: + OS.shell_open(next_version_release.html_url) + +#endregion + +#region Public Functions + +func show_updater_warning(next_version_number: Array, current_version_number: Array) -> void: + var current_version_number_0: int = current_version_number[0] as int + var current_version_number_1: int = current_version_number[1] as int + + var next_version_number_0: int = next_version_number[0] as int # Major release number in the new release + var next_version_number_1: int = next_version_number[1] as int # Minor release number in the new release + + if next_version_number_0 > current_version_number_0 or \ + next_version_number_1 > current_version_number_1: + _breaking_label.show() + _breaking_margin_container.show() + _breaking_options_button.show() + _download_button.hide() + + _download_dialogue = get_parent() + _download_dialogue.size = Vector2(_download_dialogue.size.x, _breaking_window_height) + +#endregion diff --git a/godot/addons/phantom_camera/scripts/panel/updater/update_button.gd b/godot/addons/phantom_camera/scripts/panel/updater/update_button.gd new file mode 100644 index 0000000..686535c --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/updater/update_button.gd @@ -0,0 +1,177 @@ +####################################################################### +# Credit goes to the Dialogue Manager plugin for this script +# Check it out at: https://github.com/nathanhoad/godot_dialogue_manager +####################################################################### + +@tool +extends Button + +#region Constants + +const REMOTE_RELEASE_URL: StringName = "https://api.github.com/repos/ramokz/phantom-camera/releases" +const UPDATER_CONSTANTS := preload("res://addons/phantom_camera/scripts/panel/updater/updater_constants.gd") + +#endregion + + +#region @onready + +@onready var http_request: HTTPRequest = %HTTPRequest +@onready var download_dialog: AcceptDialog = %DownloadDialog +@onready var download_update_panel: Control = %DownloadUpdatePanel +@onready var needs_reload_dialog: AcceptDialog = %NeedsReloadDialog +@onready var update_failed_dialog: AcceptDialog = %UpdateFailedDialog + +#endregion + + +#region Variables + +# The main editor plugin +var editor_plugin: EditorPlugin + +var needs_reload: bool = false + +# A lambda that gets called just before refreshing the plugin. Return false to stop the reload. +var on_before_refresh: Callable = func(): return true + +#endregion + + +#region Private Functions + +func _ready() -> void: + hide() + + # Check for updates on GitHub Releases + check_for_update() + + pressed.connect(_on_update_button_pressed) + http_request.request_completed.connect(_request_request_completed) + download_update_panel.updated.connect(_on_download_update_panel_updated) + needs_reload_dialog.confirmed.connect(_on_needs_reload_dialog_confirmed) + + +func _request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: + if result != HTTPRequest.RESULT_SUCCESS: return + + if not editor_plugin: return + var current_version: String = editor_plugin.get_version() + + # Work out the next version from the releases information on GitHub + var response: Array = JSON.parse_string(body.get_string_from_utf8()) + if typeof(response) != TYPE_ARRAY: return + + # GitHub releases are in order of creation, not order of version + var versions: Array = response.filter(func(release): + var version: String = release.tag_name.substr(1) + return version_to_number(version) > version_to_number(current_version) + ) + + if versions.size() > 0: + if ProjectSettings.get_setting(UPDATER_CONSTANTS.setting_updater_mode) == 1: ## For console output mode + + print_rich(" +[color=#3AB99A] ********[/color] +[color=#3AB99A] ************[/color] +[color=#3AB99A]**************[/color] +[color=#3AB99A]****** *** *[/color] +[color=#3AB99A]****** ***[/color] +[color=#3AB99A]********** *****[/color] +[color=#3AB99A]******** ***********[/color] +[color=#3AB99A]******** *********** **[/color] +[color=#3AB99A]********* **************[/color] +[color=#3AB99A]********** *************[/color] +[color=#3AB99A]** ** ** ******* **[/color] +[font_size=18][b]New Phantom Camera version is available[/b][/font_size]") + + if FileAccess.file_exists("res://dev_scenes/3d/dev_scene_3d.tscn"): + print_rich("[font_size=14][color=#EAA15E][b]As you're using a fork of the project, you will need to update it manually[/b][/color][/font_size]") + + print_rich("[font_size=12]If you don't want to see this message, then it can be disabled inside:\n[code]Project Settings/Phantom Camera/Updater/Show New Release Info on Editor Launch in Output[/code]") + + return + + download_update_panel.next_version_release = versions[0] + download_update_panel.show_updater_warning( + versions[0].tag_name.substr(1).split("."), + current_version.split(".") + ) + _set_scale() + editor_plugin.panel_button.add_theme_color_override("font_color", Color("#3AB99A")) + editor_plugin.panel_button.icon = load("res://addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg") + editor_plugin.panel_button.add_theme_color_override("icon_normal_color", Color("#3AB99A")) + show() + + +func _on_update_button_pressed() -> void: + if needs_reload: + var will_refresh = on_before_refresh.call() + if will_refresh: + EditorInterface.restart_editor(true) + else: + _set_scale() + download_dialog.popup_centered() + + +func _set_scale() -> void: + var scale: float = EditorInterface.get_editor_scale() + download_dialog.min_size = Vector2(300, 250) * scale + + +func _on_download_dialog_close_requested() -> void: + download_dialog.hide() + + +func _on_download_update_panel_updated(updated_to_version: String) -> void: + download_dialog.hide() + + needs_reload_dialog.dialog_text = "Reload to finish update" + needs_reload_dialog.ok_button_text = "Reload" + needs_reload_dialog.cancel_button_text = "Cancel" + needs_reload_dialog.popup_centered() + + needs_reload = true + text = "Reload Project" + + +func _on_download_update_panel_failed() -> void: + download_dialog.hide() + update_failed_dialog.dialog_text = "Updated Failed" + update_failed_dialog.popup_centered() + + +func _on_needs_reload_dialog_confirmed() -> void: + EditorInterface.restart_editor(true) + + +func _on_timer_timeout() -> void: + if not needs_reload: + check_for_update() + +#endregion + + +#region Public Functions + +# Convert a version number to an actually comparable number +func version_to_number(version: String) -> int: + var regex = RegEx.new() + regex.compile("[a-zA-Z]+") + if regex.search(str(version)): return 0 + + var bits = version.split(".") + var version_bit: int + var multiplier: int = 10000 + for i in bits.size(): + version_bit += bits[i].to_int() * multiplier / (10 ** (i)) + + return version_bit + + +func check_for_update() -> void: + if ProjectSettings.get_setting(UPDATER_CONSTANTS.setting_updater_mode) == 0: return + + http_request.request(REMOTE_RELEASE_URL) + +#endregion diff --git a/godot/addons/phantom_camera/scripts/panel/updater/updater_constants.gd b/godot/addons/phantom_camera/scripts/panel/updater/updater_constants.gd new file mode 100644 index 0000000..94ac2ad --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/updater/updater_constants.gd @@ -0,0 +1,8 @@ +extends RefCounted + +# Plugin Project Settings Sections +const setting_phantom_camera: StringName = "phantom_camera/" +const setting_updater_name: StringName = setting_phantom_camera + "updater/" + +# Updater Settings +const setting_updater_mode: StringName = setting_updater_name + "updater_mode" diff --git a/godot/addons/phantom_camera/scripts/panel/viewfinder/host_list.gd b/godot/addons/phantom_camera/scripts/panel/viewfinder/host_list.gd new file mode 100644 index 0000000..662e598 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/viewfinder/host_list.gd @@ -0,0 +1,112 @@ +@tool +extends VBoxContainer + +#region Constants + +const _constants := preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") +const _host_list_item: PackedScene = preload("res://addons/phantom_camera/panel/viewfinder/host_list/host_list_item.tscn") + +#endregion + +signal pcam_host_removed(pcam_host: PhantomCameraHost) + +@onready var _host_list_button: Button = %HostListButton +@onready var _host_list_scroll_container: ScrollContainer = %ScrollContainer +@onready var _host_list_item_container: VBoxContainer = %HostListContainer + +var _host_list_open: bool = false + +var _bottom_offset_value: float + +var _pcam_host_list: Array[PhantomCameraHost] +var _pcam_manager: Node + +var _viewfinder_panel: Control + +#region Private Functions + +func _ready() -> void: + _host_list_button.pressed.connect(_host_list_button_pressed) + if Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): + _pcam_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME) + _pcam_manager.pcam_host_removed_from_scene.connect(_remove_pcam_host) + + if not get_parent() is Control: return # To prevent errors when opening the scene on its own + _viewfinder_panel = get_parent() + _viewfinder_panel.resized.connect(_set_offset_top) + + _host_list_item_container.resized.connect(_set_offset_top) + + +func _set_offset_top() -> void: + offset_top = _set_host_list_size() + + +func _host_list_button_pressed() -> void: + _host_list_open = !_host_list_open + + var tween: Tween = create_tween() + var max_duration: float = 0.6 + + # 300 being the minimum size of the viewfinder's height + var duration: float = clampf( + max_duration / (300 / _host_list_item_container.size.y), + 0.3, + max_duration) + + tween.tween_property(self, "offset_top", _set_host_list_size(), duration)\ + .set_ease(Tween.EASE_OUT)\ + .set_trans(Tween.TRANS_QUINT) + + +func _set_host_list_size() -> float: + if not _host_list_open: + return clampf( + _viewfinder_panel.size.y - \ + _host_list_item_container.size.y - \ + _host_list_button.size.y - 20, + 0, + INF + ) + else: + return (_viewfinder_panel.size.y - _host_list_button.size.y / 2) + + +func _remove_pcam_host(pcam_host: PhantomCameraHost) -> void: + if _pcam_host_list.has(pcam_host): + _pcam_host_list.erase(pcam_host) + + var freed_pcam_host: Control + for host_list_item_instance in _host_list_item_container.get_children(): + if not host_list_item_instance.pcam_host == pcam_host: continue + freed_pcam_host = host_list_item_instance + host_list_item_instance.queue_free() + +#endregion + +#region Public Functions + +func add_pcam_host(pcam_host: PhantomCameraHost, is_default: bool) -> void: + if _pcam_host_list.has(pcam_host): return + + _pcam_host_list.append(pcam_host) + + var host_list_item_instance: PanelContainer = _host_list_item.instantiate() + var switch_pcam_host_button: Button = host_list_item_instance.get_node("%SwitchPCamHost") + if is_default: switch_pcam_host_button.button_pressed = true + + if not pcam_host.tree_exiting.is_connected(_remove_pcam_host): + pcam_host.tree_exiting.connect(_remove_pcam_host.bind(pcam_host)) + + host_list_item_instance.pcam_host = pcam_host + + _host_list_item_container.add_child(host_list_item_instance) + + +func clear_pcam_host_list() -> void: + _pcam_host_list.clear() + + for host_list_item_instance in _host_list_item_container.get_children(): + host_list_item_instance.queue_free() + +#endregion diff --git a/godot/addons/phantom_camera/scripts/panel/viewfinder/host_list_item.gd b/godot/addons/phantom_camera/scripts/panel/viewfinder/host_list_item.gd new file mode 100644 index 0000000..5707974 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/viewfinder/host_list_item.gd @@ -0,0 +1,58 @@ +@tool +extends Control + +const button_group_resource: ButtonGroup = preload("res://addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres") +const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +@onready var select_pcam_host: Button = %SelectPCamHost +@onready var switch_pcam_host: Button = %SwitchPCamHost + +var pcam_host: PhantomCameraHost: + set(value): + pcam_host = value + if not is_instance_valid(value): return + if not pcam_host.renamed.is_connected(_rename_pcam_host): + pcam_host.renamed.connect(_rename_pcam_host) + pcam_host.has_error.connect(_pcam_host_has_error) + get: + return pcam_host + +var _pcam_manager: Node + +#region Private fucntions + +func _ready() -> void: + switch_pcam_host.button_group = button_group_resource + select_pcam_host.pressed.connect(_select_pcam) + switch_pcam_host.pressed.connect(_switch_pcam_host) + + if not is_instance_valid(pcam_host): return + switch_pcam_host.text = pcam_host.name + + _pcam_host_has_error() + + +func _pcam_host_has_error() -> void: + if pcam_host.show_warning: + %ErrorPCamHost.visible = true + else: + %ErrorPCamHost.visible = false + + +func _rename_pcam_host() -> void: + switch_pcam_host.text = pcam_host.name + + +func _select_pcam() -> void: + EditorInterface.get_selection().clear() + EditorInterface.get_selection().add_node(pcam_host) + + +func _switch_pcam_host() -> void: + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + if not is_instance_valid(_pcam_manager): + _pcam_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME) + + _pcam_manager.viewfinder_pcam_host_switch.emit(pcam_host) + +#endregion diff --git a/godot/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd b/godot/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd new file mode 100644 index 0000000..fe163a7 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd @@ -0,0 +1,605 @@ +@tool +extends Control + +#region Constants + +const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +# TODO - Should be in a central location +const _camera_2d_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg") +const _camera_3d_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg") +const _pcam_host_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/phantom_camera_host.svg") +const _pcam_2D_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/phantom_camera_2d.svg") +const _pcam_3D_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/phantom_camera_3d.svg") + +const _overlay_color_alpha: float = 0.3 + +#endregion + +#region @onready + +@onready var dead_zone_center_hbox: VBoxContainer = %DeadZoneCenterHBoxContainer +@onready var dead_zone_center_center_panel: Panel = %DeadZoneCenterCenterPanel +@onready var dead_zone_left_center_panel: Panel = %DeadZoneLeftCenterPanel +@onready var dead_zone_right_center_panel: Panel = %DeadZoneRightCenterPanel +@onready var target_point: Panel = %TargetPoint + +@onready var aspect_ratio_container: AspectRatioContainer = %AspectRatioContainer +@onready var camera_viewport_panel: Panel = aspect_ratio_container.get_child(0) +@onready var _viewfinder: Control = %Viewfinder +@onready var _dead_zone_h_box_container: Control = %DeadZoneHBoxContainer +@onready var sub_viewport: SubViewport = %SubViewport + +@onready var _empty_state_control: Control = %EmptyStateControl +@onready var _empty_state_icon: TextureRect = %EmptyStateIcon +@onready var _empty_state_text: RichTextLabel = %EmptyStateText +@onready var _add_node_button: Button = %AddNodeButton +@onready var _add_node_button_text: RichTextLabel = %AddNodeTypeText + +@onready var _priority_override_button: Button = %PriorityOverrideButton +@onready var _priority_override_name_label: Label = %PriorityOverrideNameLabel + +@onready var _camera_2d: Camera2D = %Camera2D + +@onready var _pcam_host_list: VBoxContainer = %PCamHostList + +#endregion + +#region Private Variables + +var _no_open_scene_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg") +var _no_open_scene_string: String = "[b]2D[/b] or [b]3D[/b] scene open" + +var _selected_camera: Node +var _active_pcam: Node + +var _is_2d: bool + +var _pcam_manager: Node + +var _root_node: Node + +#endregion + +#region Public Variables + +var pcam_host_group: Array[PhantomCameraHost] + +var is_scene: bool + +var viewfinder_visible: bool + +var min_horizontal: float +var max_horizontal: float +var min_vertical: float +var max_vertical: float + +var pcam_host: PhantomCameraHost + +#endregion + + +#region Private Functions + +func _ready() -> void: + if not Engine.is_editor_hint(): + set_process(true) + camera_viewport_panel.self_modulate.a = 0 + + _root_node = get_tree().current_scene + + if _root_node is Node2D || _root_node is Node3D: + %SubViewportContainer.visible = false + if _root_node is Node2D: + _is_2d = true + else: + _is_2d = false + + _set_viewfinder(_root_node, false) + + if not Engine.is_editor_hint(): + _empty_state_control.visible = false + + _priority_override_button.visible = false + + # Triggered when viewport size is changed in Project Settings + ProjectSettings.settings_changed.connect(_settings_changed) + + # PCam Host List + _pcam_host_list.visible = false + _assign_manager() + _visibility_check() + + +func _pcam_host_switch(new_pcam_host: PhantomCameraHost) -> void: + _set_viewfinder_camera(new_pcam_host, true) + + +func _exit_tree() -> void: + if aspect_ratio_container.resized.is_connected(_resized): + aspect_ratio_container.resized.disconnect(_resized) + + if _add_node_button.pressed.is_connected(_visibility_check): + _add_node_button.pressed.disconnect(_visibility_check) + + if is_instance_valid(_active_pcam): + if _active_pcam.dead_zone_changed.is_connected(_on_dead_zone_changed): + _active_pcam.dead_zone_changed.disconnect(_on_dead_zone_changed) + + if _priority_override_button.pressed.is_connected(_select_override_pcam): + _priority_override_button.pressed.disconnect(_select_override_pcam) + + +func _process(_delta: float) -> void: + if Engine.is_editor_hint() and not viewfinder_visible: return + if not is_instance_valid(_active_pcam): return + + var unprojected_position_clamped: Vector2 = Vector2( + clamp(_active_pcam.viewport_position.x, min_horizontal, max_horizontal), + clamp(_active_pcam.viewport_position.y, min_vertical, max_vertical) + ) + + if not Engine.is_editor_hint(): + target_point.position = camera_viewport_panel.size * unprojected_position_clamped - target_point.size / 2 + + if not _is_2d: return + if not is_instance_valid(pcam_host): return + if not is_instance_valid(pcam_host.camera_2d): return + + var window_size_height: float = ProjectSettings.get_setting("display/window/size/viewport_height") + sub_viewport.size_2d_override = sub_viewport.size * (window_size_height / sub_viewport.size.y) + + _camera_2d.global_transform = pcam_host.camera_2d.global_transform + _camera_2d.offset = pcam_host.camera_2d.offset + _camera_2d.zoom = pcam_host.camera_2d.zoom + _camera_2d.ignore_rotation = pcam_host.camera_2d.ignore_rotation + _camera_2d.anchor_mode = pcam_host.camera_2d.anchor_mode + _camera_2d.limit_left = pcam_host.camera_2d.limit_left + _camera_2d.limit_top = pcam_host.camera_2d.limit_top + _camera_2d.limit_right = pcam_host.camera_2d.limit_right + _camera_2d.limit_bottom = pcam_host.camera_2d.limit_bottom + + +func _settings_changed() -> void: + var viewport_width: float = ProjectSettings.get_setting("display/window/size/viewport_width") + var viewport_height: float = ProjectSettings.get_setting("display/window/size/viewport_height") + var ratio: float = viewport_width / viewport_height + aspect_ratio_container.set_ratio(ratio) + camera_viewport_panel.size.x = viewport_width / (viewport_height / sub_viewport.size.y) + + # Applies Project Settings to Viewport + sub_viewport.canvas_item_default_texture_filter = ProjectSettings.get_setting("rendering/textures/canvas_textures/default_texture_filter") + + # TODO - Add resizer for Framed Viewfinder + + +func _visibility_check() -> void: + if not viewfinder_visible: return + + var pcam_host: PhantomCameraHost + var has_camera: bool = false + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + + if not Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_hosts().is_empty(): + has_camera = true + pcam_host = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_hosts()[0] + + var root: Node = EditorInterface.get_edited_scene_root() + if root is Node2D: + var camera_2d: Camera2D + + if has_camera: + camera_2d = pcam_host.camera_2d + else: + camera_2d = _get_camera_2d() + + _is_2d = true + is_scene = true + _add_node_button.visible = true + _check_camera(root, camera_2d) + elif root is Node3D: + var camera_3d: Camera3D + if has_camera: + camera_3d = pcam_host.camera_3d + elif root.get_viewport() != null: + if root.get_viewport().get_camera_3d() != null: + camera_3d = root.get_viewport().get_camera_3d() + + _is_2d = false + is_scene = true + _add_node_button.visible = true + _check_camera(root, camera_3d) + else: + # Is not a 2D or 3D scene + is_scene = false + _set_empty_viewfinder_state(_no_open_scene_string, _no_open_scene_icon) + _add_node_button.visible = false + + # Checks if a new scene is created and changes viewfinder accordingly + if not get_tree().node_added.is_connected(_node_added_to_scene): + get_tree().node_added.connect(_node_added_to_scene) + + if not _priority_override_button.pressed.is_connected(_select_override_pcam): + _priority_override_button.pressed.connect(_select_override_pcam) + + +func _node_added_to_scene(node: Node) -> void: + if node is Node2D or node is Node3D: + get_tree().node_added.disconnect(_node_added_to_scene) + _visibility_check() + + +func _get_camera_2d() -> Camera2D: + var edited_scene_root: Node = EditorInterface.get_edited_scene_root() + + if edited_scene_root == null: return null + + var viewport: Viewport = edited_scene_root.get_viewport() + if viewport == null: return null + + var viewport_rid: RID = viewport.get_viewport_rid() + if viewport_rid == null: return null + + var camerasGroupName: String = "__cameras_%d" % viewport_rid.get_id() + var cameras: Array[Node] = get_tree().get_nodes_in_group(camerasGroupName) + + for camera in cameras: + if camera is Camera2D and camera.is_current: + return camera + + return null + + +func _check_camera(root: Node, camera: Node) -> void: + var camera_string: String + var pcam_string: String + var color: Color + var camera_icon: CompressedTexture2D + var pcam_icon: CompressedTexture2D + + if _is_2d: + camera_string = _constants.CAMERA_2D_NODE_NAME + pcam_string = _constants.PCAM_2D_NODE_NAME + color = _constants.COLOR_2D + camera_icon = _camera_2d_icon + pcam_icon = _pcam_2D_icon + else: + camera_string = _constants.CAMERA_3D_NODE_NAME + pcam_string = _constants.PCAM_3D_NODE_NAME + color = _constants.COLOR_3D + camera_icon = _camera_3d_icon + pcam_icon = _pcam_3D_icon + + if camera: +# Has Camera + if camera.get_children().size() > 0: + for cam_child in camera.get_children(): + if cam_child is PhantomCameraHost: + pcam_host = cam_child + + if pcam_host: + if get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_2ds() or \ + get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_3ds(): + # Pcam exists in tree + _set_viewfinder(root, true) + _set_viewfinder_state() + %NoSupportMsg.visible = false + else: +# No PCam in scene + _update_button(pcam_string, pcam_icon, color) + _set_empty_viewfinder_state(pcam_string, pcam_icon) + else: +# No PCamHost in scene + _update_button(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon, _constants.PCAM_HOST_COLOR) + _set_empty_viewfinder_state(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon) + else: +# No PCamHost in scene + _update_button(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon, _constants.PCAM_HOST_COLOR) + _set_empty_viewfinder_state(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon) + else: +# No Camera + _update_button(camera_string, camera_icon, color) + _set_empty_viewfinder_state(camera_string, camera_icon) + + +func _update_button(text: String, icon: CompressedTexture2D, color: Color) -> void: + _add_node_button_text.set_text("[center]Add [img=32]" + icon.resource_path + "[/img] [b]"+ text + "[/b][/center]"); + var button_theme_hover: StyleBoxFlat = _add_node_button.get_theme_stylebox("hover") + button_theme_hover.border_color = color + _add_node_button.add_theme_stylebox_override("hover", button_theme_hover) + + +func _set_viewfinder_state() -> void: + _empty_state_control.visible = false + _viewfinder.visible = true + + if is_instance_valid(_active_pcam): + if _active_pcam.get_follow_mode() == _active_pcam.FollowMode.FRAMED: + _dead_zone_h_box_container.visible = true + target_point.visible = true + else: + _dead_zone_h_box_container.visible = false + target_point.visible = false + + +func _set_empty_viewfinder_state(text: String, icon: CompressedTexture2D) -> void: + _viewfinder.visible = false + _framed_view_visible(false) + + _empty_state_control.visible = true + _empty_state_icon.texture = icon + if icon == _no_open_scene_icon: + _empty_state_text.set_text("[center]No " + text + "[/center]") + else: + _empty_state_text.set_text("[center]No [b]" + text + "[/b] in scene[/center]") + + if _add_node_button.pressed.is_connected(_add_node): + _add_node_button.pressed.disconnect(_add_node) + + _add_node_button.pressed.connect(_add_node.bind(text)) + + +func _add_node(node_type: String) -> void: + var scene_root: Node = EditorInterface.get_edited_scene_root() + + match node_type: + _no_open_scene_string: + pass + _constants.CAMERA_2D_NODE_NAME: + var camera: Camera2D = Camera2D.new() + _instantiate_node(scene_root, camera, _constants.CAMERA_2D_NODE_NAME) + _constants.CAMERA_3D_NODE_NAME: + var camera: Camera3D = Camera3D.new() + _instantiate_node(scene_root, camera, _constants.CAMERA_3D_NODE_NAME) + _constants.PCAM_HOST_NODE_NAME: + var pcam_host: PhantomCameraHost = PhantomCameraHost.new() + var camera_owner: Node + if _is_2d: + camera_owner = _get_camera_2d() + else: + camera_owner = get_tree().get_edited_scene_root().get_viewport().get_camera_3d() + _instantiate_node( + scene_root, + pcam_host, + _constants.PCAM_HOST_NODE_NAME, + camera_owner + ) + _constants.PCAM_2D_NODE_NAME: + var pcam_2D: PhantomCamera2D = PhantomCamera2D.new() + _instantiate_node(scene_root, pcam_2D, _constants.PCAM_2D_NODE_NAME) + _constants.PCAM_3D_NODE_NAME: + var pcam_3D: PhantomCamera3D = PhantomCamera3D.new() + _instantiate_node(scene_root, pcam_3D, _constants.PCAM_3D_NODE_NAME) + + _visibility_check() + + +func _instantiate_node(scene_root: Node, node: Node, name: String, parent: Node = scene_root) -> void: + node.set_name(name) + parent.add_child(node) + node.owner = scene_root + + +func _set_viewfinder(root: Node, editor: bool) -> void: + pcam_host_group = get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_hosts() + if pcam_host_group.size() != 0: + if pcam_host_group.size() == 1: + _pcam_host_list.visible = false + _set_viewfinder_camera(pcam_host_group[0], editor) + else: + _pcam_host_list.visible = true + _set_viewfinder_camera(pcam_host_group[0], editor) + for i in pcam_host_group.size(): + var is_default: bool = false + if i == 0: + is_default = true + _pcam_host_list.add_pcam_host(pcam_host_group[i], is_default) + + +func _set_viewfinder_camera(new_pcam_host: PhantomCameraHost, editor: bool) -> void: + pcam_host = new_pcam_host + + if _is_2d: + _selected_camera = pcam_host.camera_2d + + if editor: + sub_viewport.disable_3d = true + pcam_host = pcam_host + _camera_2d.zoom = pcam_host.camera_2d.zoom + _camera_2d.offset = pcam_host.camera_2d.offset + _camera_2d.ignore_rotation = pcam_host.camera_2d.ignore_rotation + + sub_viewport.world_2d = pcam_host.camera_2d.get_world_2d() + sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS + sub_viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS + sub_viewport.size_2d_override_stretch = true + else: + _selected_camera = pcam_host.camera_3d + if editor: + var camera_3d_rid: RID = _selected_camera.get_camera_rid() + sub_viewport.disable_3d = false + sub_viewport.world_3d = pcam_host.camera_3d.get_world_3d() + RenderingServer.viewport_attach_camera(sub_viewport.get_viewport_rid(), camera_3d_rid) + + if _selected_camera.keep_aspect == Camera3D.KeepAspect.KEEP_HEIGHT: + aspect_ratio_container.set_stretch_mode(AspectRatioContainer.STRETCH_HEIGHT_CONTROLS_WIDTH) + else: + aspect_ratio_container.set_stretch_mode(AspectRatioContainer.STRETCH_WIDTH_CONTROLS_HEIGHT) + + set_process(true) + + if not pcam_host.viewfinder_update.is_connected(_on_update_editor_viewfinder): + pcam_host.viewfinder_update.connect(_on_update_editor_viewfinder) + + if not pcam_host.viewfinder_disable_dead_zone.is_connected(_disconnect_dead_zone): + pcam_host.viewfinder_disable_dead_zone.connect(_disconnect_dead_zone) + + if not aspect_ratio_container.resized.is_connected(_resized): + aspect_ratio_container.resized.connect(_resized) + + if is_instance_valid(pcam_host.get_active_pcam()): + _active_pcam = pcam_host.get_active_pcam() + else: + _framed_view_visible(false) + _active_pcam = null + return + + if not _active_pcam.follow_mode == PhantomCamera2D.FollowMode.FRAMED: return + + _framed_view_visible(true) + _on_dead_zone_changed() + _connect_dead_zone() + + +func _connect_dead_zone() -> void: + if not _active_pcam and is_instance_valid(pcam_host.get_active_pcam()): + _active_pcam = pcam_host.get_active_pcam() + + if not _active_pcam.dead_zone_changed.is_connected(_on_dead_zone_changed): + _active_pcam.dead_zone_changed.connect(_on_dead_zone_changed) + + _framed_view_visible(true) + _viewfinder.visible = true + _on_dead_zone_changed() + +func _disconnect_dead_zone() -> void: + if not is_instance_valid(_active_pcam): return + _framed_view_visible(_is_framed_pcam()) + + if _active_pcam.follow_mode_changed.is_connected(_check_follow_mode): + _active_pcam.follow_mode_changed.disconnect(_check_follow_mode) + + if _active_pcam.dead_zone_changed.is_connected(_on_dead_zone_changed): + _active_pcam.dead_zone_changed.disconnect(_on_dead_zone_changed) + + +func _resized() -> void: + _on_dead_zone_changed() + + +func _is_framed_pcam() -> bool: + if not is_instance_valid(pcam_host): return false + _active_pcam = pcam_host.get_active_pcam() + if not is_instance_valid(_active_pcam): return false + if not _active_pcam.follow_mode == PhantomCamera2D.FollowMode.FRAMED: return false + + return true + + +func _framed_view_visible(should_show: bool) -> void: + if should_show: + target_point.visible = true + _dead_zone_h_box_container.visible = true + else: + target_point.visible = false + _dead_zone_h_box_container.visible = false + + +func _on_dead_zone_changed() -> void: + if not is_instance_valid(_active_pcam): return + if not _active_pcam.follow_mode == _active_pcam.FollowMode.FRAMED: return + + # Waits until the camera_viewport_panel has been resized when launching the game + if camera_viewport_panel.size.x == 0: + await camera_viewport_panel.resized + + if not _active_pcam == pcam_host.get_active_pcam(): + _active_pcam == pcam_host.get_active_pcam() + + var dead_zone_width: float = _active_pcam.dead_zone_width * camera_viewport_panel.size.x + var dead_zone_height: float = _active_pcam.dead_zone_height * camera_viewport_panel.size.y + dead_zone_center_hbox.set_custom_minimum_size(Vector2(dead_zone_width, 0)) + dead_zone_center_center_panel.set_custom_minimum_size(Vector2(0, dead_zone_height)) + dead_zone_left_center_panel.set_custom_minimum_size(Vector2(0, dead_zone_height)) + dead_zone_right_center_panel.set_custom_minimum_size(Vector2(0, dead_zone_height)) + + min_horizontal = 0.5 - _active_pcam.dead_zone_width / 2 + max_horizontal = 0.5 + _active_pcam.dead_zone_width / 2 + min_vertical = 0.5 - _active_pcam.dead_zone_height / 2 + max_vertical = 0.5 + _active_pcam.dead_zone_height / 2 + + +func _check_follow_mode() -> void: + _framed_view_visible(_is_framed_pcam()) + + +func _on_update_editor_viewfinder(check_framed_view: bool = false) -> void: + _active_pcam = pcam_host.get_active_pcam() + + if not is_instance_valid(_active_pcam): return + + if not _active_pcam.follow_mode_changed.is_connected(_check_follow_mode): + _active_pcam.follow_mode_changed.connect(_check_follow_mode) + + if _active_pcam.priority_override: + _priority_override_button.visible = true + _priority_override_name_label.set_text(_active_pcam.name) + _priority_override_button.set_tooltip_text(_active_pcam.name) + else: + _priority_override_button.visible = false + + _framed_view_visible(false) + if not check_framed_view: return + if _is_framed_pcam(): _connect_dead_zone() + + +func _select_override_pcam() -> void: + EditorInterface.get_selection().clear() + EditorInterface.get_selection().add_node(_active_pcam) + + +func _assign_manager() -> void: + if not is_instance_valid(_pcam_manager): + if Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): + _pcam_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME) + _pcam_manager.pcam_host_added_to_scene.connect(_pcam_changed) + _pcam_manager.pcam_host_removed_from_scene.connect(_pcam_host_removed_from_scene) + + _pcam_manager.pcam_added_to_scene.connect(_pcam_changed) + _pcam_manager.pcam_removed_from_scene.connect(_pcam_changed) + + _pcam_manager.viewfinder_pcam_host_switch.connect(_pcam_host_switch) + + +func _pcam_host_removed_from_scene(pcam_host: PhantomCameraHost) -> void: + if _pcam_manager.phantom_camera_hosts.size() < 2: + _pcam_host_list.visible = false + + _visibility_check() + + +func _pcam_changed(pcam: Node) -> void: + _visibility_check() + +#endregion + + +#region Public Functions + +func set_visibility(visible: bool) -> void: + if visible: + viewfinder_visible = true + _visibility_check() + else: + viewfinder_visible = false + + +func update_dead_zone() -> void: + _set_viewfinder(_root_node, true) + + +## TODO - Signal can be added directly to this file with the changes in Godot 4.5 (https://github.com/godotengine/godot/pull/102986) +func scene_changed(scene_root: Node) -> void: + _assign_manager() + _priority_override_button.visible = false + _pcam_host_list.clear_pcam_host_list() + + if not scene_root is Node2D and not scene_root is Node3D: + is_scene = false + _pcam_host_list.visible = false + _set_empty_viewfinder_state(_no_open_scene_string, _no_open_scene_icon) + _add_node_button.visible = false + else: + _visibility_check() + +#endregion diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera.cs b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera.cs new file mode 100644 index 0000000..267adf0 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera.cs @@ -0,0 +1,253 @@ +using Godot; +using PhantomCamera.Noise; + +#nullable enable + +namespace PhantomCamera; + +public enum InactiveUpdateMode +{ + Always, + Never +} + +public abstract class PhantomCamera +{ + protected readonly GodotObject Node; + + public delegate void BecameActiveEventHandler(); + public delegate void BecameInactiveEventHandler(); + public delegate void FollowTargetChangedEventHandler(); + public delegate void DeadZoneChangedEventHandler(); + public delegate void TweenStartedEventHandler(); + public delegate void IsTweeningEventHandler(); + public delegate void TweenCompletedEventHandler(); + + public event BecameActiveEventHandler? BecameActive; + public event BecameInactiveEventHandler? BecameInactive; + public event FollowTargetChangedEventHandler? FollowTargetChanged; + public event DeadZoneChangedEventHandler? DeadZoneChanged; + public event TweenStartedEventHandler? TweenStarted; + public event IsTweeningEventHandler? IsTweening; + public event TweenCompletedEventHandler? TweenCompleted; + + private readonly Callable _callableBecameActive; + private readonly Callable _callableBecameInactive; + private readonly Callable _callableFollowTargetChanged; + private readonly Callable _callableDeadZoneChanged; + private readonly Callable _callableTweenStarted; + private readonly Callable _callableIsTweening; + private readonly Callable _callableTweenCompleted; + + public int Priority + { + get => (int)Node.Call(MethodName.GetPriority); + set => Node.Call(MethodName.SetPriority, value); + } + + public bool IsActive => (bool)Node.Call(MethodName.IsActive); + + public bool FollowDamping + { + get => (bool)Node.Call(MethodName.GetFollowDamping); + set => Node.Call(MethodName.SetFollowDamping, value); + } + + public bool IsFollowing => (bool)Node.Call(PhantomCamera.MethodName.IsFollowing); + + public float DeadZoneWidth + { + get => (float)Node.Get(PropertyName.DeadZoneWidth); + set => Node.Set(PropertyName.DeadZoneWidth, value); + } + + public float DeadZoneHeight + { + get => (float)Node.Get(PropertyName.DeadZoneHeight); + set => Node.Set(PropertyName.DeadZoneHeight, value); + } + + public PhantomCameraTween TweenResource + { + get => new((Resource)Node.Call(MethodName.GetTweenResource)); + set => Node.Call(MethodName.SetTweenResource, (GodotObject)value.Resource); + } + + public bool TweenSkip + { + get => (bool)Node.Call(MethodName.GetTweenSkip); + set => Node.Call(MethodName.SetTweenSkip, value); + } + + public float TweenDuration + { + get => (float)Node.Call(MethodName.GetTweenDuration); + set => Node.Call(MethodName.SetTweenDuration, value); + } + + public TransitionType TweenTransition + { + get => (TransitionType)(int)Node.Call(MethodName.GetTweenTransition); + set => Node.Call(MethodName.SetTweenTransition, (int)value); + } + + public EaseType TweenEase + { + get => (EaseType)(int)Node.Call(MethodName.GetTweenEase); + set => Node.Call(MethodName.SetTweenEase, (int)value); + } + + public bool TweenOnLoad + { + get => (bool)Node.Call(MethodName.GetTweenOnLoad); + set => Node.Call(MethodName.SetTweenOnLoad, value); + } + + public InactiveUpdateMode InactiveUpdateMode + { + get => (InactiveUpdateMode)(int)Node.Call(MethodName.GetInactiveUpdateMode); + set => Node.Call(MethodName.SetInactiveUpdateMode, (int)value); + } + + public int HostLayers + { + get => (int)Node.Call(MethodName.GetHostLayers); + set => Node.Call(MethodName.SetHostLayers, value); + } + + public int NoiseEmitterLayer + { + get => (int)Node.Call(MethodName.GetNoiseEmitterLayer); + set => Node.Call(MethodName.SetNoiseEmitterLayer, value); + } + + public void TeleportPosition() + { + Node.Call(MethodName.TeleportPosition); + } + + public void SetHostLayersValue(int layer, bool enabled) + { + Node.Call(MethodName.SetHostLayersValue, layer, enabled); + } + + protected PhantomCamera(GodotObject phantomCameraNode) + { + Node = phantomCameraNode; + + _callableBecameActive = Callable.From(() => BecameActive?.Invoke()); + _callableBecameInactive = Callable.From(() => BecameInactive?.Invoke()); + _callableFollowTargetChanged = Callable.From(() => FollowTargetChanged?.Invoke()); + _callableDeadZoneChanged = Callable.From(() => DeadZoneChanged?.Invoke()); + _callableTweenStarted = Callable.From(() => TweenStarted?.Invoke()); + _callableIsTweening = Callable.From(() => IsTweening?.Invoke()); + _callableTweenCompleted = Callable.From(() => TweenCompleted?.Invoke()); + + Node.Connect(SignalName.BecameActive, _callableBecameActive); + Node.Connect(SignalName.BecameInactive, _callableBecameInactive); + Node.Connect(SignalName.FollowTargetChanged, _callableFollowTargetChanged); + Node.Connect(SignalName.DeadZoneChanged, _callableDeadZoneChanged); + Node.Connect(SignalName.TweenStarted, _callableTweenStarted); + Node.Connect(SignalName.IsTweening, _callableIsTweening); + Node.Connect(SignalName.TweenCompleted, _callableTweenCompleted); + } + + ~PhantomCamera() + { + Node.Disconnect(SignalName.BecameActive, _callableBecameActive); + Node.Disconnect(SignalName.BecameInactive, _callableBecameInactive); + Node.Disconnect(SignalName.FollowTargetChanged, _callableFollowTargetChanged); + Node.Disconnect(SignalName.DeadZoneChanged, _callableDeadZoneChanged); + Node.Disconnect(SignalName.TweenStarted, _callableTweenStarted); + Node.Disconnect(SignalName.IsTweening, _callableIsTweening); + Node.Disconnect(SignalName.TweenCompleted, _callableTweenCompleted); + } + + public static class MethodName + { + public const string GetFollowMode = "get_follow_mode"; + public const string IsActive = "is_active"; + + public const string GetPriority = "get_priority"; + public const string SetPriority = "set_priority"; + + public const string IsFollowing = "is_following"; + + public const string GetFollowTarget = "get_follow_target"; + public const string SetFollowTarget = "set_follow_target"; + + public const string GetFollowTargets = "get_follow_targets"; + public const string SetFollowTargets = "set_follow_targets"; + + public const string TeleportPosition = "teleport_position"; + + public const string AppendFollowTargets = "append_follow_targets"; + public const string AppendFollowTargetsArray = "append_follow_targets_array"; + public const string EraseFollowTargets = "erase_follow_targets"; + + public const string GetFollowPath = "get_follow_path"; + public const string SetFollowPath = "set_follow_path"; + + public const string GetFollowOffset = "get_follow_offset"; + public const string SetFollowOffset = "set_follow_offset"; + + public const string GetFollowDamping = "get_follow_damping"; + public const string SetFollowDamping = "set_follow_damping"; + + public const string GetFollowDampingValue = "get_follow_damping_value"; + public const string SetFollowDampingValue = "set_follow_damping_value"; + + public const string GetFollowAxisLock = "get_follow_axis_lock"; + public const string SetFollowAxisLock = "set_follow_axis_lock"; + + public const string GetTweenResource = "get_tween_resource"; + public const string SetTweenResource = "set_tween_resource"; + + public const string GetTweenSkip = "get_tween_skip"; + public const string SetTweenSkip = "set_tween_skip"; + + public const string GetTweenDuration = "get_tween_duration"; + public const string SetTweenDuration = "set_tween_duration"; + + public const string GetTweenTransition = "get_tween_transition"; + public const string SetTweenTransition = "set_tween_transition"; + + public const string GetTweenEase = "get_tween_ease"; + public const string SetTweenEase = "set_tween_ease"; + + public const string GetTweenOnLoad = "get_tween_on_load"; + public const string SetTweenOnLoad = "set_tween_on_load"; + + public const string GetInactiveUpdateMode = "get_inactive_update_mode"; + public const string SetInactiveUpdateMode = "set_inactive_update_mode"; + + public const string GetHostLayers = "get_host_layers"; + public const string SetHostLayers = "set_host_layers"; + public const string SetHostLayersValue = "set_host_layers_value"; + + public const string GetNoiseEmitterLayer = "get_noise_emitter_layer"; + public const string SetNoiseEmitterLayer = "set_noise_emitter_layer"; + + public const string EmitNoise = "emit_noise"; + } + + public static class PropertyName + { + public const string DeadZoneWidth = "dead_zone_width"; + public const string DeadZoneHeight = "dead_zone_height"; + } + + public static class SignalName + { + public const string BecameActive = "became_active"; + public const string BecameInactive = "became_inactive"; + public const string FollowTargetChanged = "follow_target_changed"; + public const string DeadZoneChanged = "dead_zone_changed"; + public const string DeadZoneReached = "dead_zone_reached"; + public const string TweenStarted = "tween_started"; + public const string IsTweening = "is_tweening"; + public const string TweenCompleted = "tween_completed"; + public const string TweenInterrupted = "tween_interrupted"; + public const string NoiseEmitted = "noise_emitted"; + } +} diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera2D.cs b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera2D.cs new file mode 100644 index 0000000..65c937b --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera2D.cs @@ -0,0 +1,315 @@ +using System.Linq; +using Godot; +using Godot.Collections; +using PhantomCamera.Noise; + +#nullable enable + +namespace PhantomCamera; + +public enum FollowMode2D +{ + None, + Glued, + Simple, + Group, + Path, + Framed +} + +public enum FollowLockAxis2D +{ + None, + X, + Y, + XY +} + +public static class PhantomCamera2DExtensions +{ + public static PhantomCamera2D AsPhantomCamera2D(this Node2D node2D) + { + return new PhantomCamera2D(node2D); + } + + public static PhantomCameraNoiseEmitter2D AsPhantomCameraNoiseEmitter2D(this Node2D node2D) + { + return new PhantomCameraNoiseEmitter2D(node2D); + } + + public static PhantomCameraNoise2D AsPhantomCameraNoise2D(this Resource resource) + { + return new PhantomCameraNoise2D(resource); + } +} + +public class PhantomCamera2D : PhantomCamera +{ + public Node2D Node2D => (Node2D)Node; + + public delegate void TweenInterruptedEventHandler(Node2D pCam); + public delegate void DeadZoneReachedEventHandler(Vector2 side); + public delegate void NoiseEmittedEventHandler(Transform2D output); + + public event TweenInterruptedEventHandler? TweenInterrupted; + public event DeadZoneReachedEventHandler? DeadZoneReached; + public event NoiseEmittedEventHandler? NoiseEmitted; + + private readonly Callable _callableTweenInterrupted; + private readonly Callable _callableDeadZoneReached; + private readonly Callable _callableNoiseEmitted; + + public Node2D FollowTarget + { + get => (Node2D)Node2D.Call(PhantomCamera.MethodName.GetFollowTarget); + set => Node2D.Call(PhantomCamera.MethodName.SetFollowTarget, value); + } + + public Node2D[] FollowTargets + { + get => Node2D.Call(PhantomCamera.MethodName.GetFollowTargets).AsGodotArray().ToArray(); + set => Node2D.Call(PhantomCamera.MethodName.SetFollowTargets, new Array(value)); + } + + public void AppendFollowTargets(Node2D target) => Node2D.Call(PhantomCamera.MethodName.AppendFollowTargets, target); + public void AppendFollowTargetsArray(Node2D[] targets) => Node2D.Call(PhantomCamera.MethodName.AppendFollowTargetsArray, targets); + public void EraseFollowTargets(Node2D target) => Node2D.Call(PhantomCamera.MethodName.EraseFollowTargets, target); + + public FollowMode2D FollowMode => (FollowMode2D)(int)Node.Call(PhantomCamera.MethodName.GetFollowMode); + + public Path2D FollowPath + { + get => (Path2D)Node2D.Call(PhantomCamera.MethodName.GetFollowPath); + set => Node2D.Call(PhantomCamera.MethodName.SetFollowPath, value); + } + + public Vector2 FollowOffset + { + get => (Vector2)Node2D.Call(PhantomCamera.MethodName.GetFollowOffset); + set => Node2D.Call(PhantomCamera.MethodName.SetFollowOffset, value); + } + + public Vector2 FollowDampingValue + { + get => (Vector2)Node2D.Call(PhantomCamera.MethodName.GetFollowDampingValue); + set => Node2D.Call(PhantomCamera.MethodName.SetFollowDampingValue, value); + } + + public FollowLockAxis2D FollowAxisLock + { + get => (FollowLockAxis2D)(int)Node2D.Call(PhantomCamera.MethodName.GetFollowAxisLock); + set => Node2D.Call(PhantomCamera.MethodName.SetFollowAxisLock, (int)value); + } + + public Vector2 Zoom + { + get => (Vector2)Node2D.Call(MethodName.GetZoom); + set => Node2D.Call(MethodName.SetZoom, value); + } + + public bool SnapToPixel + { + get => (bool)Node2D.Call(MethodName.GetSnapToPixel); + set => Node2D.Call(MethodName.SetSnapToPixel, value); + } + + public int LimitLeft + { + get => (int)Node2D.Call(MethodName.GetLimitLeft); + set => Node2D.Call(MethodName.SetLimitLeft, value); + } + + public int LimitTop + { + get => (int)Node2D.Call(MethodName.GetLimitTop); + set => Node2D.Call(MethodName.SetLimitTop, value); + } + + public int LimitRight + { + get => (int)Node2D.Call(MethodName.GetLimitRight); + set => Node2D.Call(MethodName.SetLimitRight, value); + } + + public int LimitBottom + { + get => (int)Node2D.Call(MethodName.GetLimitBottom); + set => Node2D.Call(MethodName.SetLimitBottom, value); + } + + public Vector4I LimitMargin + { + get => (Vector4I)Node2D.Call(MethodName.GetLimitMargin); + set => Node2D.Call(MethodName.SetLimitMargin, value); + } + + public bool AutoZoom + { + get => (bool)Node2D.Call(MethodName.GetAutoZoom); + set => Node2D.Call(MethodName.SetAutoZoom, value); + } + + public float AutoZoomMin + { + get => (float)Node2D.Call(MethodName.GetAutoZoomMin); + set => Node2D.Call(MethodName.SetAutoZoomMin, value); + } + + public float AutoZoomMax + { + get => (float)Node2D.Call(MethodName.GetAutoZoomMax); + set => Node2D.Call(MethodName.SetAutoZoomMax, value); + } + + public Vector4 AutoZoomMargin + { + get => (Vector4)Node2D.Call(MethodName.GetAutoZoomMargin); + set => Node2D.Call(MethodName.SetAutoZoomMargin, value); + } + + public bool DrawLimits + { + get => (bool)Node2D.Get(PropertyName.DrawLimits); + set => Node2D.Set(PropertyName.DrawLimits, value); + } + + public PhantomCameraNoise2D Noise + { + get => new((Resource)Node2D.Call(MethodName.GetNoise)); + set => Node2D.Call(MethodName.SetNoise, (GodotObject)value.Resource); + } + + public void EmitNoise(Transform2D transform) => Node2D.Call(PhantomCamera.MethodName.EmitNoise, transform); + + public NodePath LimitTarget + { + get => (NodePath)Node2D.Call(MethodName.GetLimitTarget); + set => Node2D.Call(MethodName.SetLimitTarget, value); + } + + public static PhantomCamera2D FromScript(string path) => new(GD.Load(path).New().AsGodotObject()); + public static PhantomCamera2D FromScript(GDScript script) => new(script.New().AsGodotObject()); + + public PhantomCamera2D(GodotObject phantomCameraNode) : base(phantomCameraNode) + { + _callableTweenInterrupted = Callable.From(pCam => TweenInterrupted?.Invoke(pCam)); + _callableDeadZoneReached = Callable.From((Vector2 side) => DeadZoneReached?.Invoke(side)); + _callableNoiseEmitted = Callable.From((Transform2D output) => NoiseEmitted?.Invoke(output)); + + Node2D.Connect(SignalName.TweenInterrupted, _callableTweenInterrupted); + Node2D.Connect(SignalName.DeadZoneReached, _callableDeadZoneReached); + Node2D.Connect(SignalName.NoiseEmitted, _callableNoiseEmitted); + } + + ~PhantomCamera2D() + { + Node2D.Disconnect(SignalName.TweenInterrupted, _callableTweenInterrupted); + Node2D.Disconnect(SignalName.DeadZoneReached, _callableDeadZoneReached); + Node2D.Disconnect(SignalName.NoiseEmitted, _callableNoiseEmitted); + } + + public void SetLimitTarget(TileMap tileMap) + { + Node2D.Call(MethodName.SetLimitTarget, tileMap.GetPath()); + } + + public void SetLimitTarget(TileMapLayer tileMapLayer) + { + Node2D.Call(MethodName.SetLimitTarget, tileMapLayer.GetPath()); + } + + public void SetLimitTarget(CollisionShape2D shape2D) + { + Node2D.Call(MethodName.SetLimitTarget, shape2D.GetPath()); + } + + public LimitTargetQueryResult? GetLimitTarget() + { + var result = (NodePath)Node2D.Call(MethodName.GetLimitTarget); + return result.IsEmpty ? null : new LimitTargetQueryResult(Node2D.GetNode(result)); + } + + public void SetLimit(Side side, int value) + { + Node2D.Call(MethodName.SetLimit, (int)side, value); + } + + public int GetLimit(Side side) + { + return (int)Node2D.Call(MethodName.GetLimit, (int)side); + } + + public new static class MethodName + { + public const string GetZoom = "get_zoom"; + public const string SetZoom = "set_zoom"; + + public const string GetSnapToPixel = "get_snap_to_pixel"; + public const string SetSnapToPixel = "set_snap_to_pixel"; + + public const string GetLimit = "get_limit"; + public const string SetLimit = "set_limit"; + + public const string GetLimitLeft = "get_limit_left"; + public const string SetLimitLeft = "set_limit_left"; + + public const string GetLimitTop = "get_limit_top"; + public const string SetLimitTop = "set_limit_top"; + + public const string GetLimitRight = "get_limit_right"; + public const string SetLimitRight = "set_limit_right"; + + public const string GetLimitBottom = "get_limit_bottom"; + public const string SetLimitBottom = "set_limit_bottom"; + + public const string GetLimitTarget = "get_limit_target"; + public const string SetLimitTarget = "set_limit_target"; + + public const string GetLimitMargin = "get_limit_margin"; + public const string SetLimitMargin = "set_limit_margin"; + + public const string GetAutoZoom = "get_auto_zoom"; + public const string SetAutoZoom = "set_auto_zoom"; + + public const string GetAutoZoomMin = "get_auto_zoom_min"; + public const string SetAutoZoomMin = "set_auto_zoom_min"; + + public const string GetAutoZoomMax = "get_auto_zoom_max"; + public const string SetAutoZoomMax = "set_auto_zoom_max"; + + public const string GetAutoZoomMargin = "get_auto_zoom_margin"; + public const string SetAutoZoomMargin = "set_auto_zoom_margin"; + + public const string GetNoise = "get_noise"; + public const string SetNoise = "set_noise"; + } + + public new static class PropertyName + { + public const string DrawLimits = "draw_limits"; + } +} + +public class LimitTargetQueryResult(GodotObject godotObject) +{ + public bool IsTileMap => godotObject.IsClass("TileMap"); + + public bool IsTileMapLayer => godotObject.IsClass("TileMapLayer"); + + public bool IsCollisionShape2D => godotObject.IsClass("CollisionShape2D"); + + public TileMap? AsTileMap() + { + return IsTileMap ? (TileMap)godotObject : null; + } + + public TileMapLayer? AsTileMapLayer() + { + return IsTileMapLayer ? (TileMapLayer)godotObject : null; + } + + public CollisionShape2D? AsCollisionShape2D() + { + return IsCollisionShape2D ? (CollisionShape2D)godotObject : null; + } +} diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera3D.cs b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera3D.cs new file mode 100644 index 0000000..591cecf --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCamera3D.cs @@ -0,0 +1,475 @@ +using System.Linq; +using Godot; +using Godot.Collections; +using PhantomCamera.Noise; + +#nullable enable + +namespace PhantomCamera; + +public enum LookAtMode +{ + None, + Mimic, + Simple, + Group +} + +public enum FollowMode3D +{ + None, + Glued, + Simple, + Group, + Path, + Framed, + ThirdPerson +} + +public enum FollowLockAxis3D +{ + None, + X, + Y, + Z, + XY, + XZ, + YZ, + XYZ +} + +public static class PhantomCamera3DExtensions +{ + public static PhantomCamera3D AsPhantomCamera3D(this Node3D node3D) + { + return new PhantomCamera3D(node3D); + } + + public static PhantomCameraNoiseEmitter3D AsPhantomCameraNoiseEmitter3D(this Node3D node3D) + { + return new PhantomCameraNoiseEmitter3D(node3D); + } + + public static PhantomCameraNoise3D AsPhantomCameraNoise3D(this Resource resource) + { + return new PhantomCameraNoise3D(resource); + } + + public static Camera3DResource AsCamera3DResource(this Resource resource) + { + return new Camera3DResource(resource); + } + + public static Vector3 GetThirdPersonRotation(this PhantomCamera3D pCam3D) => + (Vector3)pCam3D.Node3D.Call(PhantomCamera3D.MethodName.GetThirdPersonRotation); + + public static void SetThirdPersonRotation(this PhantomCamera3D pCam3D, Vector3 rotation) => + pCam3D.Node3D.Call(PhantomCamera3D.MethodName.SetThirdPersonRotation, rotation); + + public static Vector3 GetThirdPersonRotationDegrees(this PhantomCamera3D pCam3D) => + (Vector3)pCam3D.Node3D.Call(PhantomCamera3D.MethodName.GetThirdPersonRotationDegrees); + + public static void SetThirdPersonDegrees(this PhantomCamera3D pCam3D, Vector3 rotation) => + pCam3D.Node3D.Call(PhantomCamera3D.MethodName.SetThirdPersonRotationDegrees, rotation); + + public static Quaternion GetThirdPersonQuaternion(this PhantomCamera3D pCam3D) => + (Quaternion)pCam3D.Node3D.Call(PhantomCamera3D.MethodName.GetThirdPersonQuaternion); + + public static void SetThirdPersonQuaternion(this PhantomCamera3D pCam3D, Quaternion quaternion) => + pCam3D.Node3D.Call(PhantomCamera3D.MethodName.SetThirdPersonQuaternion, quaternion); + +} + +public class PhantomCamera3D : PhantomCamera +{ + public Node3D Node3D => (Node3D)Node; + + public delegate void LookAtTargetChangedEventHandler(); + public delegate void DeadZoneReachedEventHandler(); + public delegate void Camera3DResourceChangedEventHandler(); + public delegate void Camera3DResourcePropertyChangedEventHandler(StringName property, Variant value); + public delegate void TweenInterruptedEventHandler(Node3D pCam); + public delegate void NoiseEmittedEventHandler(Transform3D output); + + public event LookAtTargetChangedEventHandler? LookAtTargetChanged; + public event DeadZoneReachedEventHandler? DeadZoneReached; + public event Camera3DResourceChangedEventHandler? Camera3DResourceChanged; + public event Camera3DResourcePropertyChangedEventHandler? Camera3DResourcePropertyChanged; + public event TweenInterruptedEventHandler? TweenInterrupted; + public event NoiseEmittedEventHandler? NoiseEmitted; + + private readonly Callable _callableLookAtTargetChanged; + private readonly Callable _callableDeadZoneReached; + private readonly Callable _callableCamera3DResourceChanged; + private readonly Callable _callableCamera3DResourcePropertyChanged; + private readonly Callable _callableTweenInterrupted; + private readonly Callable _callableNoiseEmitted; + + public Node3D FollowTarget + { + get => (Node3D)Node3D.Call(PhantomCamera.MethodName.GetFollowTarget); + set => Node3D.Call(PhantomCamera.MethodName.SetFollowTarget, value); + } + + public Node3D[] FollowTargets + { + get => Node3D.Call(PhantomCamera.MethodName.GetFollowTargets).AsGodotArray().ToArray(); + set => Node3D.Call(PhantomCamera.MethodName.SetFollowTargets, new Array(value)); + } + + public void AppendFollowTarget(Node3D target) => Node3D.Call(PhantomCamera.MethodName.AppendFollowTargets, target); + public void AppendFollowTargetArray(Node3D[] targets) => Node3D.Call(PhantomCamera.MethodName.AppendFollowTargetsArray, targets); + public void EraseFollowTarget(Node3D target) => Node3D.Call(PhantomCamera.MethodName.EraseFollowTargets, target); + + public FollowMode3D FollowMode => (FollowMode3D)(int)Node.Call(PhantomCamera.MethodName.GetFollowMode); + + public Path3D FollowPath + { + get => (Path3D)Node3D.Call(PhantomCamera.MethodName.GetFollowPath); + set => Node3D.Call(PhantomCamera.MethodName.SetFollowPath, value); + } + + public Vector3 FollowOffset + { + get => (Vector3)Node3D.Call(PhantomCamera.MethodName.GetFollowOffset); + set => Node3D.Call(PhantomCamera.MethodName.SetFollowOffset, value); + } + + public Vector3 FollowDampingValue + { + get => (Vector3)Node3D.Call(PhantomCamera.MethodName.GetFollowDampingValue); + set => Node3D.Call(PhantomCamera.MethodName.SetFollowDampingValue, value); + } + + public FollowLockAxis3D FollowAxisLock + { + get => (FollowLockAxis3D)(int)Node3D.Call(PhantomCamera.MethodName.GetFollowAxisLock); + set => Node3D.Call(PhantomCamera.MethodName.SetFollowAxisLock, (int)value); + } + + public LookAtMode LookAtMode => (LookAtMode)(int)Node3D.Call(MethodName.GetLookAtMode); + + public Camera3DResource Camera3DResource + { + get => new((Resource)Node3D.Call(MethodName.GetCamera3DResource)); + set => Node3D.Call(MethodName.SetCamera3DResource, value.Resource); + } + + public float SpringLength + { + get => (float)Node3D.Call(MethodName.GetSpringLength); + set => Node3D.Call(MethodName.SetSpringLength, value); + } + + public float FollowDistance + { + get => (float)Node3D.Call(MethodName.GetFollowDistance); + set => Node3D.Call(MethodName.SetFollowDistance, value); + } + + public bool AutoFollowDistance + { + get => (bool)Node3D.Call(MethodName.GetAutoFollowDistance); + set => Node3D.Call(MethodName.SetAutoFollowDistance, value); + } + + public float AutoFollowDistanceMin + { + get => (float)Node3D.Call(MethodName.GetAutoFollowDistanceMin); + set => Node3D.Call(MethodName.SetAutoFollowDistanceMin, value); + } + + public float AutoFollowDistanceMax + { + get => (float)Node3D.Call(MethodName.GetAutoFollowDistanceMax); + set => Node3D.Call(MethodName.SetAutoFollowDistanceMax, value); + } + + public float AutoFollowDistanceDivisor + { + get => (float)Node3D.Call(MethodName.GetAutoFollowDistanceDivisor); + set => Node3D.Call(MethodName.SetAutoFollowDistanceDivisor, value); + } + + public Node3D LookAtTarget + { + get => (Node3D)Node3D.Call(MethodName.GetLookAtTarget); + set => Node3D.Call(MethodName.SetLookAtTarget, value); + } + + public Node3D[] LookAtTargets + { + get => Node3D.Call(MethodName.GetLookAtTargets).AsGodotArray().ToArray(); + set => Node3D.Call(MethodName.SetLookAtTargets, new Array(value)); + } + + public bool IsLooking => (bool)Node3D.Call(MethodName.IsLooking); + + public int CollisionMask + { + get => (int)Node3D.Call(MethodName.GetCollisionMask); + set => Node3D.Call(MethodName.SetCollisionMask, value); + } + + public void SetCollisionMaskValue(int maskLayer, bool enable) => + Node3D.Call(MethodName.SetCollisionMaskValue, maskLayer, enable); + + public Shape3D Shape + { + get => (Shape3D)Node3D.Call(MethodName.GetShape); + set => Node3D.Call(MethodName.SetShape, value); + } + + public float Margin + { + get => (float)Node3D.Call(MethodName.GetMargin); + set => Node3D.Call(MethodName.SetMargin, value); + } + + public Vector3 LookAtOffset + { + get => (Vector3)Node3D.Call(MethodName.GetLookAtOffset); + set => Node3D.Call(MethodName.SetLookAtOffset, value); + } + + public bool LookAtDamping + { + get => (bool)Node3D.Call(MethodName.GetLookAtDamping); + set => Node3D.Call(MethodName.SetLookAtDamping, value); + } + + public float LookAtDampingValue + { + get => (float)Node3D.Call(MethodName.GetLookAtDampingValue); + set => Node3D.Call(MethodName.SetLookAtDampingValue, value); + } + + public Node3D Up + { + get => (Node3D)Node3D.Call(MethodName.GetUp); + set => Node3D.Call(MethodName.SetUp, value); + } + + public Vector3 UpTarget + { + get => (Vector3)Node3D.Call(MethodName.GetUpTarget); + set => Node3D.Call(MethodName.SetUpTarget, value); + } + + public int CullMask + { + get => (int)Node3D.Call(MethodName.GetCullMask); + set => Node3D.Call(MethodName.SetCullMask, value); + } + + public float HOffset + { + get => (float)Node3D.Call(MethodName.GetHOffset); + set => Node3D.Call(MethodName.SetHOffset, value); + } + + public float VOffset + { + get => (float)Node3D.Call(MethodName.GetVOffset); + set => Node3D.Call(MethodName.SetVOffset, value); + } + + public ProjectionType Projection + { + get => (ProjectionType)(int)Node3D.Call(MethodName.GetProjection); + set => Node3D.Call(MethodName.SetProjection, (int)value); + } + + public float Fov + { + get => (float)Node3D.Call(MethodName.GetFov); + set => Node3D.Call(MethodName.SetFov, value); + } + + public float Size + { + get => (float)Node3D.Call(MethodName.GetSize); + set => Node3D.Call(MethodName.SetSize, value); + } + + public Vector2 FrustumOffset + { + get => (Vector2)Node3D.Call(MethodName.GetFrustumOffset); + set => Node3D.Call(MethodName.SetFrustumOffset, value); + } + + public float Far + { + get => (float)Node3D.Call(MethodName.GetFar); + set => Node3D.Call(MethodName.SetFar, value); + } + + public float Near + { + get => (float)Node3D.Call(MethodName.GetNear); + set => Node3D.Call(MethodName.SetNear, value); + } + + public Environment Environment + { + get => (Environment)Node3D.Call(MethodName.GetEnvironment); + set => Node3D.Call(MethodName.SetEnvironment, value); + } + + public CameraAttributes Attributes + { + get => (CameraAttributes)Node3D.Call(MethodName.GetAttributes); + set => Node3D.Call(MethodName.SetAttributes, value); + } + + public PhantomCameraNoise3D Noise + { + get => new((Resource)Node3D.Call(MethodName.GetNoise)); + set => Node3D.Call(MethodName.SetNoise, (GodotObject)value.Resource); + } + + public void EmitNoise(Transform3D transform) => Node3D.Call(PhantomCamera.MethodName.EmitNoise, transform); + + public static PhantomCamera3D FromScript(string path) => new(GD.Load(path).New().AsGodotObject()); + public static PhantomCamera3D FromScript(GDScript script) => new(script.New().AsGodotObject()); + + public PhantomCamera3D(GodotObject phantomCamera3DNode) : base(phantomCamera3DNode) + { + _callableLookAtTargetChanged = Callable.From(() => LookAtTargetChanged?.Invoke()); + _callableDeadZoneReached = Callable.From(() => DeadZoneReached?.Invoke()); + _callableCamera3DResourceChanged = Callable.From(() => Camera3DResourceChanged?.Invoke()); + _callableCamera3DResourcePropertyChanged = Callable.From((StringName property, Variant value) => + Camera3DResourcePropertyChanged?.Invoke(property, value)); + _callableTweenInterrupted = Callable.From(pCam => TweenInterrupted?.Invoke(pCam)); + _callableNoiseEmitted = Callable.From((Transform3D output) => NoiseEmitted?.Invoke(output)); + + Node3D.Connect(SignalName.LookAtTargetChanged, _callableLookAtTargetChanged); + Node3D.Connect(PhantomCamera.SignalName.DeadZoneReached, _callableDeadZoneReached); + Node3D.Connect(SignalName.Camera3DResourceChanged, _callableCamera3DResourceChanged); + Node3D.Connect(SignalName.Camera3DResourcePropertyChanged, _callableCamera3DResourcePropertyChanged); + Node3D.Connect(PhantomCamera.SignalName.TweenInterrupted, _callableTweenInterrupted); + Node3D.Connect(PhantomCamera.SignalName.NoiseEmitted, _callableNoiseEmitted); + } + + ~PhantomCamera3D() + { + Node3D.Disconnect(SignalName.LookAtTargetChanged, _callableLookAtTargetChanged); + Node3D.Disconnect(PhantomCamera.SignalName.DeadZoneReached, _callableDeadZoneReached); + Node3D.Disconnect(SignalName.Camera3DResourceChanged, _callableCamera3DResourceChanged); + Node3D.Disconnect(SignalName.Camera3DResourcePropertyChanged, _callableCamera3DResourcePropertyChanged); + Node3D.Disconnect(PhantomCamera.SignalName.TweenInterrupted, _callableTweenInterrupted); + Node3D.Disconnect(PhantomCamera.SignalName.NoiseEmitted, _callableNoiseEmitted); + } + + public new static class MethodName + { + public const string GetLookAtMode = "get_look_at_mode"; + + public const string GetCamera3DResource = "get_camera_3d_resource"; + public const string SetCamera3DResource = "set_camera_3d_resource"; + + public const string GetThirdPersonRotation = "get_third_person_rotation"; + public const string SetThirdPersonRotation = "set_third_person_rotation"; + + public const string GetThirdPersonRotationDegrees = "get_third_person_rotation_degrees"; + public const string SetThirdPersonRotationDegrees = "set_third_person_rotation_degrees"; + + public const string GetThirdPersonQuaternion = "get_third_person_quaternion"; + public const string SetThirdPersonQuaternion = "set_third_person_quaternion"; + + public const string GetSpringLength = "get_spring_length"; + public const string SetSpringLength = "set_spring_length"; + + public const string GetFollowDistance = "get_follow_distance"; + public const string SetFollowDistance = "set_follow_distance"; + + public const string GetAutoFollowDistance = "get_auto_follow_distance"; + public const string SetAutoFollowDistance = "set_auto_follow_distance"; + + public const string GetAutoFollowDistanceMin = "get_auto_follow_distance_min"; + public const string SetAutoFollowDistanceMin = "set_auto_follow_distance_min"; + + public const string GetAutoFollowDistanceMax = "get_auto_follow_distance_max"; + public const string SetAutoFollowDistanceMax = "set_auto_follow_distance_max"; + + public const string GetAutoFollowDistanceDivisor = "get_auto_follow_distance_divisor"; + public const string SetAutoFollowDistanceDivisor = "set_auto_follow_distance_divisor"; + + public const string GetLookAtTarget = "get_look_at_target"; + public const string SetLookAtTarget = "set_look_at_target"; + + public const string GetLookAtTargets = "get_look_at_targets"; + public const string SetLookAtTargets = "set_look_at_targets"; + + public const string IsLooking = "is_looking"; + + public const string GetUp = "get_up"; + public const string SetUp = "set_up"; + + public const string GetUpTarget = "get_up_target"; + public const string SetUpTarget = "set_up_target"; + + public const string GetCollisionMask = "get_collision_mask"; + public const string SetCollisionMask = "set_collision_mask"; + + public const string SetCollisionMaskValue = "set_collision_mask_value"; + + public const string GetShape = "get_shape"; + public const string SetShape = "set_shape"; + + public const string GetMargin = "get_margin"; + public const string SetMargin = "set_margin"; + + public const string GetLookAtOffset = "get_look_at_offset"; + public const string SetLookAtOffset = "set_look_at_offset"; + + public const string GetLookAtDamping = "get_look_at_damping"; + public const string SetLookAtDamping = "set_look_at_damping"; + + public const string GetLookAtDampingValue = "get_look_at_damping_value"; + public const string SetLookAtDampingValue = "set_look_at_damping_value"; + + public const string GetCullMask = "get_cull_mask"; + public const string SetCullMask = "set_cull_mask"; + + public const string GetHOffset = "get_h_offset"; + public const string SetHOffset = "set_h_offset"; + + public const string GetVOffset = "get_v_offset"; + public const string SetVOffset = "set_v_offset"; + + public const string GetProjection = "get_projection"; + public const string SetProjection = "set_projection"; + + public const string GetFov = "get_fov"; + public const string SetFov = "set_fov"; + + public const string GetSize = "get_size"; + public const string SetSize = "set_size"; + + public const string GetFrustumOffset = "get_frustum_offset"; + public const string SetFrustumOffset = "set_frustum_offset"; + + public const string GetFar = "get_far"; + public const string SetFar = "set_far"; + + public const string GetNear = "get_near"; + public const string SetNear = "set_near"; + + public const string GetEnvironment = "get_environment"; + public const string SetEnvironment = "set_environment"; + + public const string GetAttributes = "get_attributes"; + public const string SetAttributes = "set_attributes"; + + public const string GetNoise = "get_noise"; + public const string SetNoise = "set_noise"; + } + + public new static class SignalName + { + public const string LookAtTargetChanged = "look_at_target_changed"; + public const string Camera3DResourceChanged = "camera_3d_resource_changed"; + public const string Camera3DResourcePropertyChanged = "camera_3d_resource_property_changed"; + } +} diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter2D.cs b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter2D.cs new file mode 100644 index 0000000..1e73b57 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter2D.cs @@ -0,0 +1,83 @@ +using Godot; + +namespace PhantomCamera.Noise; + +public class PhantomCameraNoiseEmitter2D(GodotObject node) +{ + public Node2D Node2D = (Node2D)node; + + public PhantomCameraNoise2D Noise + { + get => new((Resource)Node2D.Call(MethodName.GetNoise)); + set => Node2D.Call(MethodName.SetNoise, (GodotObject)value.Resource); + } + + public bool Continuous + { + get => (bool)Node2D.Call(MethodName.GetContinuous); + set => Node2D.Call(MethodName.SetContinuous, value); + } + + public float GrowthTime + { + get => (float)Node2D.Call(MethodName.GetGrowthTime); + set => Node2D.Call(MethodName.SetGrowthTime, value); + } + + public float Duration + { + get => (float)Node2D.Call(MethodName.GetDuration); + set => Node2D.Call(MethodName.SetDuration, value); + } + + public float DecayTime + { + get => (float)Node2D.Call(MethodName.GetDecayTime); + set => Node2D.Call(MethodName.SetDecayTime, value); + } + + public int NoiseEmitterLayer + { + get => (int)Node2D.Call(MethodName.GetNoiseEmitterLayer); + set => Node2D.Call(MethodName.SetNoiseEmitterLayer, value); + } + + public void SetNoiseEmitterLayerValue(int layer, bool value) => + Node2D.Call(MethodName.SetNoiseEmitterLayerValue, layer, value); + + public void Emit() => Node2D.Call(MethodName.Emit); + + public bool IsEmitting() => (bool)Node2D.Call(MethodName.IsEmitting); + + public void Stop() => Node2D.Call(MethodName.Stop); + + public void Toggle() => Node2D.Call(MethodName.Toggle); + + public static class MethodName + { + public const string GetNoise = "get_noise"; + public const string SetNoise = "set_noise"; + + public const string GetContinuous = "get_continuous"; + public const string SetContinuous = "set_continuous"; + + public const string GetGrowthTime = "get_growth_time"; + public const string SetGrowthTime = "set_growth_time"; + + public const string GetDuration = "get_duration"; + public const string SetDuration = "set_duration"; + + public const string GetDecayTime = "get_decay_time"; + public const string SetDecayTime = "set_decay_time"; + + public const string GetNoiseEmitterLayer = "get_noise_emitter_layer"; + public const string SetNoiseEmitterLayer = "set_noise_emitter_layer"; + + public const string SetNoiseEmitterLayerValue = "set_noise_emitter_layer_value"; + + public const string Emit = "emit"; + public const string IsEmitting = "is_emitting"; + public const string Stop = "stop"; + public const string Toggle = "toggle"; + } +} diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter3D.cs b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter3D.cs new file mode 100644 index 0000000..18620b2 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/PhantomCameraNoiseEmitter3D.cs @@ -0,0 +1,83 @@ +using Godot; + +namespace PhantomCamera.Noise; + +public class PhantomCameraNoiseEmitter3D(GodotObject node) +{ + public Node3D Node3D = (Node3D)node; + + public PhantomCameraNoise3D Noise + { + get => new((Resource)Node3D.Call(MethodName.GetNoise)); + set => Node3D.Call(MethodName.SetNoise, (GodotObject)value.Resource); + } + + public bool Continuous + { + get => (bool)Node3D.Call(MethodName.GetContinuous); + set => Node3D.Call(MethodName.SetContinuous, value); + } + + public float GrowthTime + { + get => (float)Node3D.Call(MethodName.GetGrowthTime); + set => Node3D.Call(MethodName.SetGrowthTime, value); + } + + public float Duration + { + get => (float)Node3D.Call(MethodName.GetDuration); + set => Node3D.Call(MethodName.SetDuration, value); + } + + public float DecayTime + { + get => (float)Node3D.Call(MethodName.GetDecayTime); + set => Node3D.Call(MethodName.SetDecayTime, value); + } + + public int NoiseEmitterLayer + { + get => (int)Node3D.Call(MethodName.GetNoiseEmitterLayer); + set => Node3D.Call(MethodName.SetNoiseEmitterLayer, value); + } + + public void SetNoiseEmitterLayerValue(int layer, bool value) => + Node3D.Call(MethodName.SetNoiseEmitterLayerValue, layer, value); + + public void Emit() => Node3D.Call(MethodName.Emit); + + public bool IsEmitting() => (bool)Node3D.Call(MethodName.IsEmitting); + + public void Stop() => Node3D.Call(MethodName.Stop); + + public void Toggle() => Node3D.Call(MethodName.Toggle); + + public static class MethodName + { + public const string GetNoise = "get_noise"; + public const string SetNoise = "set_noise"; + + public const string GetContinuous = "get_continuous"; + public const string SetContinuous = "set_continuous"; + + public const string GetGrowthTime = "get_growth_time"; + public const string SetGrowthTime = "set_growth_time"; + + public const string GetDuration = "get_duration"; + public const string SetDuration = "set_duration"; + + public const string GetDecayTime = "get_decay_time"; + public const string SetDecayTime = "set_decay_time"; + + public const string GetNoiseEmitterLayer = "get_noise_emitter_layer"; + public const string SetNoiseEmitterLayer = "set_noise_emitter_layer"; + + public const string SetNoiseEmitterLayerValue = "set_noise_emitter_layer_value"; + + public const string Emit = "emit"; + public const string IsEmitting = "is_emitting"; + public const string Stop = "stop"; + public const string Toggle = "toggle"; + } +} diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd new file mode 100644 index 0000000..e4f1977 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd @@ -0,0 +1,1614 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_2d.svg") +class_name PhantomCamera2D +extends Node2D + +## Controls a scene's [Camera2D] and applies logic to it. +## +## The scene's [param Camera2D] will follow the position of the +## [param PhantomCamera2D] with the highest priority. +## Each instance can have different positional and rotational logic applied +## to them. + +#region Constants + +const _constants := preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +#endregion + +#region Signals + +## Emitted when the [param PhantomCamera2D] becomes active. +signal became_active + +## Emitted when the [param PhantomCamera2D] becomes inactive. +signal became_inactive + +## Emitted when the follow_mode changes. +## Note: This is for internal use only +signal follow_mode_changed + +## Emitted when [member follow_target] changes. +signal follow_target_changed + +## Emitted when dead zones changes.[br] +## [b]Note:[/b] Only applicable in [param Framed] [enum FollowMode]. +signal dead_zone_changed + +## Emitted when a target touches the edge of the dead zone in [param Framed] [enum FollowMode]. +signal dead_zone_reached(side: Vector2) + +## Emitted when the [param Camera2D] starts to tween to another [param PhantomCamera2D]. +signal tween_started + +## Emitted when the [param Camera2D] is to tweening towards another [param PhantomCamera2D]. +signal is_tweening + +## Emitted when the tween is interrupted due to another [param PhantomCamera2D] +## becoming active. The argument is the [param PhantomCamera2D] that interrupted +## the tween. +signal tween_interrupted(pcam_2d: PhantomCamera2D) + +## Emitted when the [param Camera2D] completes its tween to the +## [param PhantomCamera2D]. +signal tween_completed + +## Emitted when Noise should be applied to the Camera2D. +signal noise_emitted(noise_output: Transform2D) + +signal physics_target_changed + +#endregion + +#region Enums + +## Determines the positional logic for a given [param PhantomCamera2D] +## [br][br] +## The different modes have different functionalities and purposes, so choosing +## the correct one depends on what each [param PhantomCamera2D] is meant to do. +enum FollowMode { + NONE = 0, ## Default - No follow logic is applied. + GLUED = 1, ## Sticks to its target. + SIMPLE = 2, ## Follows its target with an optional offset. + GROUP = 3, ## Follows multiple targets with option to dynamically reframe itself. + PATH = 4, ## Follows a target while being positionally confined to a [Path2D] node. + FRAMED = 5, ## Applies a dead zone on the frame and only follows its target when it tries to leave it. +} + +## Determines how often an inactive [param PhantomCamera2D] should update +## its positional and rotational values. This is meant to reduce the amount +## of calculations inactive [param PhantomCamera2D] are doing when idling to +## improve performance. +enum InactiveUpdateMode { + ALWAYS, ## Always updates the [param PhantomCamera2D], even when it's inactive. + NEVER, ## Never updates the [param PhantomCamera2D] when it's inactive. Reduces the amount of computational resources when inactive. +# EXPONENTIALLY, +} + +enum FollowLockAxis { + NONE = 0, + X = 1, + Y = 2, + XY = 3, +} + +#endregion + +#region Exported Properties + +## To quickly preview a [param PhantomCamera2D] without adjusting its +## [member priority], this property allows the selected PCam to ignore the +## Priority system altogether and forcefully become the active one. It's +## partly designed to work within the Viewfinder, and will be disabled when +## running a build export of the game. +@export var priority_override: bool = false: + set(value): + priority_override = value + if Engine.is_editor_hint(): + if value: + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).pcam_priority_override.emit(self, true) + else: + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).pcam_priority_override.emit(self, false) + get: + return priority_override + + +## It defines which [param PhantomCamera2D] a scene's [param Camera2D] should +## be corresponding with and be attached to. This is decided by the PCam with +## the highest [param Priority]. +## [br][br] +## Changing [param Priority] will send an event to the scene's +## [PhantomCameraHost], which will then determine whether if the +## [param Priority] value is greater than or equal to the currently +## highest [param PhantomCamera2D]'s in the scene. The [param PhantomCamera2D] +## with the highest value will then reattach the [param Camera2D] accordingly. +@export var priority: int = 0: + set = set_priority, + get = get_priority + + +## Determines the positional logic for a given [param PhantomCamera2D]. +## The different modes have different functionalities and purposes, so +## choosing the correct one depends on what each [param PhantomCamera2D] +## is meant to do. +@export var follow_mode: FollowMode = FollowMode.NONE: + set(value): + follow_mode = value + + if follow_mode == FollowMode.NONE: + _should_follow = false + top_level = false + _is_parents_physics() + notify_property_list_changed() + return + + match follow_mode: + FollowMode.PATH: + if is_instance_valid(follow_path): + _should_follow_checker() + FollowMode.GROUP: + _follow_targets_size_check() + _: + _should_follow_checker() + + if follow_mode == FollowMode.FRAMED: + if _follow_framed_initial_set and follow_target: + _follow_framed_initial_set = false + dead_zone_changed.connect(_on_dead_zone_changed) + else: + if dead_zone_changed.is_connected(_on_dead_zone_changed): + dead_zone_changed.disconnect(_on_dead_zone_changed) + + top_level = true + follow_mode_changed.emit() + notify_property_list_changed() + get: + return follow_mode + +## Determines which target should be followed. +## The [param Camera2D] will follow the position of the Follow Target +## based on the [member follow_mode] type and its parameters. +@export var follow_target: Node2D = null: + set = set_follow_target, + get = get_follow_target + +### Defines the targets that the [param PhantomCamera2D] should be following. +@export var follow_targets: Array[Node2D] = []: + set = set_follow_targets, + get = get_follow_targets + +## Determines the [Path2D] the [param PhantomCamera2D] +## should be bound to. +## The [param PhantomCamera2D] will follow the position of the +## [member follow_target] while sticking to the closest point on this path. +@export var follow_path: Path2D = null: + set = set_follow_path, + get = get_follow_path + + +## Applies a zoom level to the [param PhantomCamera2D], which effectively +## overrides the [param zoom] property of the [param Camera2D] node. +@export var zoom: Vector2 = Vector2.ONE: + set = set_zoom, + get = get_zoom + + +## If enabled, will snap the [param Camera2D] to whole pixels as it moves. +## [br][br] +## This should be particularly useful in pixel art projects, +## where assets should always be aligned to the monitor's pixels to avoid +## unintended stretching. +@export var snap_to_pixel: bool = false: + set = set_snap_to_pixel, + get = get_snap_to_pixel + + +## Enables a preview of what the [PhantomCamera2D] will see in the +## scene. It works identically to how a [param Camera2D] shows which area +## will be visible during runtime. Likewise, this too will be affected by the +## [member zoom] property and the [param viewport_width] and +## [param Viewport Height] defined in the [param Project Settings]. +@export var frame_preview: bool = true: + set(value): + frame_preview = value + queue_redraw() + get: + return frame_preview + + +## Defines how the [param PhantomCamera2D] transition between one another. +## Changing the tween values for a given [param PhantomCamera2D] +## determines how transitioning to that instance will look like. +## This is a resource type that can be either used for one +## [param PhantomCamera] or reused across multiple - both 2D and 3D. +## By default, all [param PhantomCameras] will use a [param linear] +## transition, [param easeInOut] ease with a [param 1s] duration. +@export var tween_resource: PhantomCameraTween = PhantomCameraTween.new(): + set = set_tween_resource, + get = get_tween_resource + +## If enabled, the moment a [param PhantomCamera2D] is instantiated into +## a scene, and has the highest priority, it will perform its tween transition. +## This is most obvious if a [param PhantomCamera2D] has a long duration and +## is attached to a playable character that can be moved the moment a scene +## is loaded. Disabling the [param tween_on_load] property will +## disable this behaviour and skip the tweening entirely when instantiated. +@export var tween_on_load: bool = true: + set = set_tween_on_load, + get = get_tween_on_load + + +## Determines how often an inactive [param PhantomCamera2D] should update +## its positional and rotational values. This is meant to reduce the amount +## of calculations inactive [param PhantomCamera2Ds] are doing when idling +## to improve performance. +@export var inactive_update_mode: InactiveUpdateMode = InactiveUpdateMode.ALWAYS + + +## Determines which layers this [param PhantomCamera2D] should be able to communicate with [PhantomCameraHost] nodes.[br] +## A corresponding layer needs to be set on the [PhantomCameraHost] node. +@export_flags_2d_render var host_layers: int = 1: + set = set_host_layers, + get = get_host_layers + + +@export_group("Follow Parameters") +## Offsets the [member follow_target] position. +@export var follow_offset: Vector2 = Vector2.ZERO: + set = set_follow_offset, + get = get_follow_offset + +## Applies a damping effect on the [param Camera2D]'s movement. +## Leading to heavier / slower camera movement as the targeted node moves around. +## This is useful to avoid sharp and rapid camera movement. +@export var follow_damping: bool = false: + set = set_follow_damping, + get = get_follow_damping + +## Defines the damping amount. The ideal range should be somewhere between 0-1.[br][br] +## The damping amount can be specified in the individual axis.[br][br] +## [b]Lower value[/b] = faster / sharper camera movement.[br] +## [b]Higher value[/b] = slower / heavier camera movement. +@export var follow_damping_value: Vector2 = Vector2(0.1, 0.1): + set = set_follow_damping_value, + get = get_follow_damping_value + +## Prevents the [param PhantomCamera2D] from moving in a designated axis. +## This can be enabled or disabled at runtime or from the editor directly. +@export var follow_axis_lock: FollowLockAxis = FollowLockAxis.NONE: + set = set_lock_axis, + get = get_lock_axis +var _follow_axis_is_locked: bool = false +var _follow_axis_lock_value: Vector2 = Vector2.ZERO + + +@export_subgroup("Follow Group") +## Enables the [param PhantomCamera2D] to dynamically zoom in and out based on +## the targets' distances between each other. +## Once enabled, the [param Camera2D] will stay as zoomed in as possible, +## limited by the [member auto_zoom_max] and start zooming out as the targets +## move further apart, limited by the [member auto_zoom_min]. +## Note: Enabling this property hides and disables the [member zoom] property +## as this effectively overrides that value. +@export var auto_zoom: bool = false: + set = set_auto_zoom, + get = get_auto_zoom + +## Sets the param minimum zoom amount, in other words how far away the +## [param Camera2D] can be from scene.[br][br] +## This only works when [member auto_zoom] is enabled. +@export var auto_zoom_min: float = 1: + set = set_auto_zoom_min, + get = get_auto_zoom_min + +## Sets the maximum zoom amount, in other words how close the [param Camera2D] +## can move towards the scene.[br][br] +## This only works when [member auto_zoom] is enabled. +@export var auto_zoom_max: float = 5: + set = set_auto_zoom_max, + get = get_auto_zoom_max + +## Determines how close to the edges the targets are allowed to be. +## This is useful to avoid targets being cut off at the edges of the screen. +## [br][br] +## The Vector4 parameter order goes: [param Left] - [param Top] - [param Right] +## - [param Bottom]. +@export var auto_zoom_margin: Vector4 = Vector4.ZERO: + set = set_auto_zoom_margin, + get = get_auto_zoom_margin + + +@export_subgroup("Dead Zones") +## Defines the horizontal dead zone area. While the target is within it, the +## [param PhantomCamera2D] will not move in the horizontal axis. +## If the targeted node leaves the horizontal bounds, the +## [param PhantomCamera2D] will follow the target horizontally to keep +## it within bounds. +@export_range(0, 1) var dead_zone_width: float = 0: + set(value): + dead_zone_width = value + dead_zone_changed.emit() + get: + return dead_zone_width + +## Defines the vertical dead zone area. While the target is within it, the +## [param PhantomCamera2D] will not move in the vertical axis. +## If the targeted node leaves the vertical bounds, the +## [param PhantomCamera2D] will follow the target horizontally to keep +## it within bounds. +@export_range(0, 1) var dead_zone_height: float = 0: + set(value): + dead_zone_height = value + dead_zone_changed.emit() + get: + return dead_zone_height + +## Enables the [param dead zones] to be visible when running the game from the editor. +## [br] +## [param dead zones] will never be visible in build exports. +@export var show_viewfinder_in_play: bool = false + + +@export_group("Limit") + +## Shows the [param Camera2D]'s built-in limit border.[br] +## The [param PhantomCamera2D] and [param Camera2D] can move around anywhere within it. +@export var draw_limits: bool = false: + set(value): + _draw_limits = value + if Engine.is_editor_hint(): + _draw_camera_2d_limit() + get: + return _draw_limits + +## Defines the left side of the [param Camera2D] limit. +## The camera will not be able to move past this point. +@export var limit_left: int = -10000000: + set = set_limit_left, + get = get_limit_left +## Defines the top side of the [param Camera2D] limit. +## The camera will not be able to move past this point. +@export var limit_top: int = -10000000: + set = set_limit_top, + get = get_limit_top +## Defines the right side of the [param Camera2D] limit. +## The camera will not be able to move past this point. +@export var limit_right: int = 10000000: + set = set_limit_right, + get = get_limit_right +## Defines the bottom side of the [param Camera2D] limit. +## The camera will not be able to move past this point. +@export var limit_bottom: int = 10000000: + set = set_limit_bottom, + get = get_limit_bottom + +## Allows for setting either a [TileMap], [TileMapLayer] or [CollisionShape2D] node to +## automatically apply a limit size instead of manually adjusting the Left, +## Top, Right and Left properties.[br][br] +## [b]TileMap / TileMapLayer[/b][br] +## The Limit will update after the [TileSet] of the [TileMap] / [TileMapLayer] has changed.[br] +## [b]Note:[/b] The limit size will only update after closing the TileMap editor +## bottom panel. +## [br][br] +## [b]CollisionShape2D[/b][br] +## The limit will update in realtime as the Shape2D changes its size. +## Note: For performance reasons, resizing the [Shape2D] during runtime will not change the Limits sides. +@export_node_path("TileMap", "Node2D", "CollisionShape2D") var limit_target: NodePath = NodePath(""): + set = set_limit_target, + get = get_limit_target + +## Applies an offset to the [TileMap]/[TileMapLayer] Limit or [Shape2D] Limit. +## The values goes from [param Left], [param Top], [param Right] +## and [param Bottom]. +@export var limit_margin: Vector4i = Vector4.ZERO: + set = set_limit_margin, + get = get_limit_margin +#@export var limit_smoothed: bool = false: # TODO - Needs proper support + #set = set_limit_smoothing, + #get = get_limit_smoothing + +@export_group("Noise") +## Applies a noise, or shake, to a [Camera2D].[br] +## Once set, the noise will run continuously after the tween to the [PhantomCamera2D] is complete. +@export var noise: PhantomCameraNoise2D = null: + set = set_noise, + get = get_noise + +## If true, will trigger the noise while in the editor.[br] +## Useful in cases where you want to temporarily disable the noise in the editor without removing +## the resource.[br][br] +## [b]Note:[/b] This property has no effect on runtime behaviour. +@export var _preview_noise: bool = true: + set(value): + _preview_noise = value + if not value: + _transform_noise = Transform2D() + +## Enable a corresponding layer for a [member PhantomCameraNoiseEmitter2D.noise_emitter_layer] +## to make this [PhantomCamera2D] be affect by it. +@export_flags_2d_render var noise_emitter_layer: int = 0: + set = set_noise_emitter_layer, + get = get_noise_emitter_layer + +#region Private Variables + +var _is_active: bool = false + +var _should_follow: bool = false +var _follow_framed_offset: Vector2 = Vector2.ZERO +var _follow_target_physics_based: bool = false +var _physics_interpolation_enabled: bool = false # NOTE - Enable for Godot 4.3 and when PhysicsInterpolationMode bug is resolved + +var _has_multiple_follow_targets: bool = false +var _follow_targets_single_target_index: int = 0 +var _follow_targets: Array[Node2D] = [] + +var _follow_velocity_ref: Vector2 = Vector2.ZERO # Stores and applies the velocity of the movement + +var _has_follow_path: bool = false + +var _tween_skip: bool = false + +## Defines the position of the [member follow_target] within the viewport.[br] +## This is only used for when [member follow_mode] is set to [param Framed]. +var _follow_framed_initial_set: bool = false + +static var _draw_limits: bool = false + +var _limit_sides: Vector4i = _limit_sides_default +var _limit_sides_default: Vector4i = Vector4i(-10000000, -10000000, 10000000, 10000000) + +var _limit_node: Node2D = null +var _tile_size_perspective_scaler: Vector2 = Vector2.ONE + +var _limit_inactive_pcam: bool = false + +var _follow_target_position: Vector2 = Vector2.ZERO + +var _transform_output: Transform2D = Transform2D() +var _transform_noise: Transform2D = Transform2D() + +var _has_noise_resource: bool = false + +# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box. +var _phantom_camera_manager: Node = null + +#endregion + +#region Public Variables + +var tween_duration: float: + set = set_tween_duration, + get = get_tween_duration +var tween_transition: PhantomCameraTween.TransitionType: + set = set_tween_transition, + get = get_tween_transition +var tween_ease: PhantomCameraTween.EaseType: + set = set_tween_ease, + get = get_tween_ease + +var viewport_position: Vector2 + +#endregion + +#region Private Functions + +func _validate_property(property: Dictionary) -> void: + ################ + ## Follow Target + ################ + if property.name == "follow_target": + if follow_mode == FollowMode.NONE or \ + follow_mode == FollowMode.GROUP: + property.usage = PROPERTY_USAGE_NO_EDITOR + + elif property.name == "follow_path" and \ + follow_mode != FollowMode.PATH: + property.usage = PROPERTY_USAGE_NO_EDITOR + + + #################### + ## Follow Parameters + #################### + if follow_mode == FollowMode.NONE: + match property.name: + "follow_offset", \ + "follow_damping", \ + "follow_damping_value", \ + "follow_axis_lock": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_offset": + if follow_mode == FollowMode.PATH or \ + follow_mode == FollowMode.GLUED: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_damping_value" and not follow_damping: + property.usage = PROPERTY_USAGE_NO_EDITOR + + ############### + ## Follow Group + ############### + if follow_mode != FollowMode.GROUP: + match property.name: + "follow_targets", \ + "auto_zoom": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if not auto_zoom or follow_mode != FollowMode.GROUP: + match property.name: + "auto_zoom_min", \ + "auto_zoom_max", \ + "auto_zoom_margin": + property.usage = PROPERTY_USAGE_NO_EDITOR + + ################ + ## Follow Framed + ################ + if not follow_mode == FollowMode.FRAMED: + match property.name: + "dead_zone_width", \ + "dead_zone_height", \ + "show_viewfinder_in_play": + property.usage = PROPERTY_USAGE_NO_EDITOR + + ####### + ## Zoom + ####### + if property.name == "zoom" and follow_mode == FollowMode.GROUP and auto_zoom: + property.usage = PROPERTY_USAGE_NO_EDITOR + + ######## + ## Limit + ######## + if is_instance_valid(_limit_node): + match property.name: + "limit_left", \ + "limit_top", \ + "limit_right", \ + "limit_bottom": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "limit_margin" and not _limit_node: + property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _enter_tree() -> void: + _phantom_camera_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME) + _tween_skip = !tween_on_load + + _phantom_camera_manager.pcam_added(self) + + priority_override = false + + _should_follow_checker() + if follow_mode == FollowMode.GROUP: + _follow_targets_size_check() + elif follow_mode == FollowMode.NONE: + _is_parents_physics() + + if not visibility_changed.is_connected(_check_visibility): + visibility_changed.connect(_check_visibility) + + update_limit_all_sides() + + + +func _exit_tree() -> void: + if not follow_mode == FollowMode.GROUP: + follow_targets = [] + + if not is_instance_valid(_phantom_camera_manager): return + _phantom_camera_manager.pcam_removed(self) + + +func _ready() -> void: + if is_instance_valid(follow_target): + _transform_output.origin = _get_target_position_offset() + else: + _transform_output = global_transform + + _phantom_camera_manager.noise_2d_emitted.connect(_noise_emitted) + + if not Engine.is_editor_hint(): + _preview_noise = true + + if follow_mode == FollowMode.GROUP: + _follow_targets_size_check() + + +func _process(delta: float) -> void: + if _follow_target_physics_based or _is_active: return + process_logic(delta) + + +func _physics_process(delta: float) -> void: + if not _follow_target_physics_based or _is_active: return + process_logic(delta) + + +func process_logic(delta: float) -> void: + if _is_active: + if _has_noise_resource and _preview_noise: + _transform_noise = noise.get_noise_transform(delta) + else: + match inactive_update_mode: + InactiveUpdateMode.NEVER: return + InactiveUpdateMode.ALWAYS: + # Only triggers if limit isn't default + if _limit_inactive_pcam: + global_position = _set_limit_clamp_position(global_position) + # InactiveUpdateMode.EXPONENTIALLY: + # TODO - Trigger positional updates less frequently as more PCams gets added + + _limit_checker() + + if _should_follow: + _follow(delta) + else: + _transform_output = global_transform + + if _follow_axis_is_locked: + match follow_axis_lock: + FollowLockAxis.X: + _transform_output.origin.x = _follow_axis_lock_value.x + FollowLockAxis.Y: + _transform_output.origin.y = _follow_axis_lock_value.y + FollowLockAxis.XY: + _transform_output.origin.x = _follow_axis_lock_value.x + _transform_output.origin.y = _follow_axis_lock_value.y + + +func _limit_checker() -> void: + ## TODO - Needs to see if this can be triggerd only from CollisionShape2D Transform changes + if not Engine.is_editor_hint(): return + if draw_limits: + update_limit_all_sides() + + +func _follow(delta: float) -> void: + _set_follow_position() + _interpolate_position(_follow_target_position, delta) + + +func _set_follow_position() -> void: + match follow_mode: + FollowMode.GLUED: + _follow_target_position = follow_target.global_position + + FollowMode.SIMPLE: + _follow_target_position = _get_target_position_offset() + + FollowMode.GROUP: + if _has_multiple_follow_targets: + var rect: Rect2 = Rect2(_follow_targets[0].global_position, Vector2.ZERO) + for target in _follow_targets: + rect = rect.expand(target.global_position) + if auto_zoom: + rect = rect.grow_individual( + auto_zoom_margin.x, + auto_zoom_margin.y, + auto_zoom_margin.z, + auto_zoom_margin.w + ) + + if rect.size.x > rect.size.y * _phantom_camera_manager.screen_size.aspect(): + zoom = clamp(_phantom_camera_manager.screen_size.x / rect.size.x, auto_zoom_min, auto_zoom_max) * Vector2.ONE + else: + zoom = clamp(_phantom_camera_manager.screen_size.y / rect.size.y, auto_zoom_min, auto_zoom_max) * Vector2.ONE + _follow_target_position = rect.get_center() + follow_offset + else: + _follow_target_position = follow_targets[_follow_targets_single_target_index].global_position + follow_offset + + FollowMode.PATH: + var path_position: Vector2 = follow_path.global_position + + _follow_target_position = \ + follow_path.curve.get_closest_point( + _get_target_position_offset() - path_position + ) + path_position + + FollowMode.FRAMED: + if not Engine.is_editor_hint(): + if not _is_active: + _follow_target_position = _get_target_position_offset() + else: + viewport_position = (get_follow_target().get_global_transform_with_canvas().get_origin() + follow_offset) / get_viewport_rect().size + var framed_side_offset: Vector2 = _get_framed_side_offset() + + if framed_side_offset != Vector2.ZERO: + var glo_pos: Vector2 + var target_position: Vector2 = _get_target_position_offset() + _follow_framed_offset + + if dead_zone_width == 0 || dead_zone_height == 0: + if dead_zone_width == 0 && dead_zone_height != 0: + _follow_target_position = _get_target_position_offset() + elif dead_zone_width != 0 && dead_zone_height == 0: + glo_pos = _get_target_position_offset() + glo_pos.x += target_position.x - global_position.x + _follow_target_position = glo_pos + else: + _follow_target_position = _get_target_position_offset() + + # If a horizontal dead zone is reached + if framed_side_offset.x != 0 and framed_side_offset.y == 0: + _follow_target_position.y = _transform_output.origin.y + _follow_target_position.x = target_position.x + _follow_framed_offset.y = global_position.y - _get_target_position_offset().y + dead_zone_reached.emit(Vector2(framed_side_offset.x, 0)) + # If a vertical dead zone is reached + elif framed_side_offset.x == 0 and framed_side_offset.y != 0: + _follow_target_position.x = _transform_output.origin.x + _follow_target_position.y = target_position.y + _follow_framed_offset.x = global_position.x - _get_target_position_offset().x + dead_zone_reached.emit(Vector2(0, framed_side_offset.y)) + # If a deadzone corner is reached + else: + _follow_target_position = target_position + dead_zone_reached.emit(Vector2(framed_side_offset.x, framed_side_offset.y)) + else: + _follow_framed_offset = _transform_output.origin - _get_target_position_offset() + return + else: + _follow_target_position = _get_target_position_offset() + + +func _set_follow_velocity(index: int, value: float): + _follow_velocity_ref[index] = value + + +func _interpolate_position(target_position: Vector2, delta: float) -> void: + if _limit_inactive_pcam and not _tween_skip: + target_position = _set_limit_clamp_position(target_position) + + global_position = target_position + if follow_damping and not Engine.is_editor_hint(): + var output_position: Vector2 + for i in 2: + output_position[i] = _smooth_damp( + global_position[i], + _transform_output.origin[i], + i, + _follow_velocity_ref[i], + _set_follow_velocity, + follow_damping_value[i], + delta + ) + _transform_output = Transform2D(global_rotation, output_position) + else: + _transform_output = Transform2D(global_rotation, target_position) + + +func _smooth_damp(target_axis: float, self_axis: float, index: int, current_velocity: float, set_velocity: Callable, damping_time: float, delta: float) -> float: + damping_time = maxf(0.0001, damping_time) + var omega: float = 2 / damping_time + var x: float = omega * delta + var exponential: float = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x) + var diff: float = self_axis - target_axis + var _target_axis: float = target_axis + + var max_change: float = INF * damping_time + diff = clampf(diff, -max_change, max_change) + target_axis = self_axis - diff + + var temp: float = (current_velocity + omega * diff) * delta + set_velocity.call(index, (current_velocity - omega * temp) * exponential) + var output: float = target_axis + (diff + temp) * exponential + + ## To prevent overshooting + if (_target_axis - self_axis > 0.0) == (output > _target_axis): + output = _target_axis + set_velocity.call(index, (output - _target_axis) / delta) + + return output + + +func _set_limit_clamp_position(value: Vector2) -> Vector2: + var camera_frame_rect_size: Vector2 = _camera_frame_rect().size + value.x = clampf(value.x, _limit_sides.x + camera_frame_rect_size.x / 2, _limit_sides.z - camera_frame_rect_size.x / 2) + value.y = clampf(value.y, _limit_sides.y + camera_frame_rect_size.y / 2, _limit_sides.w - camera_frame_rect_size.y / 2) + return value + + +func _draw() -> void: + if not Engine.is_editor_hint(): return + + if frame_preview and not _is_active: + draw_rect(_camera_frame_rect(), Color("3ab99a"), false, 2) + + +func _camera_frame_rect() -> Rect2: + var screen_size_zoom: Vector2 = Vector2(_phantom_camera_manager.screen_size.x / get_zoom().x, _phantom_camera_manager.screen_size.y / get_zoom().y) + + return Rect2(-screen_size_zoom / 2, screen_size_zoom) + + +func _on_tile_map_changed() -> void: + update_limit_all_sides() + + +func _get_target_position_offset() -> Vector2: + return follow_target.global_position + follow_offset + + +func _on_dead_zone_changed() -> void: + global_position = _get_target_position_offset() + + +func _get_framed_side_offset() -> Vector2: + var frame_out_bounds: Vector2 + + if viewport_position.x < 0.5 - dead_zone_width / 2: + # Is outside left edge + frame_out_bounds.x = -1 + + if viewport_position.y < 0.5 - dead_zone_height / 2: + # Is outside top edge + frame_out_bounds.y = 1 + + if viewport_position.x > 0.5 + dead_zone_width / 2: + # Is outside right edge + frame_out_bounds.x = 1 + + if viewport_position.y > 0.5001 + dead_zone_height / 2: # 0.501 to resolve an issue where the bottom vertical Dead Zone never becoming 0 when the Dead Zone Vertical parameter is set to 0 + # Is outside bottom edge + frame_out_bounds.y = -1 + + return frame_out_bounds + + +func _draw_camera_2d_limit() -> void: + if not is_instance_valid(_phantom_camera_manager): return + _phantom_camera_manager.draw_limit_2d.emit(draw_limits) + + +func _check_limit_is_not_default() -> void: + if _limit_sides == _limit_sides_default: + _limit_inactive_pcam = false + else: + _limit_inactive_pcam = true + + +func _check_visibility() -> void: + _phantom_camera_manager.pcam_visibility_changed.emit(self) + + +func _follow_target_tree_exiting(target: Node) -> void: + if target == follow_target: + _should_follow = false + if _follow_targets.has(target): + _follow_targets.erase(target) + + +func _should_follow_checker() -> void: + if follow_mode == FollowMode.NONE: + _should_follow = false + return + + if not follow_mode == FollowMode.GROUP: + if is_instance_valid(follow_target): + _should_follow = true + else: + _should_follow = false + + +func _follow_targets_size_check() -> void: + var targets_size: int = 0 + _follow_target_physics_based = false + _follow_targets = [] + for i in follow_targets.size(): + if follow_targets[i] == null: continue + if follow_targets[i].is_inside_tree(): + _follow_targets.append(follow_targets[i]) + targets_size += 1 + _follow_targets_single_target_index = i + _check_physics_body(follow_targets[i]) + if not follow_targets[i].tree_exiting.is_connected(_follow_target_tree_exiting): + follow_targets[i].tree_exiting.connect(_follow_target_tree_exiting.bind(follow_targets[i])) + + match targets_size: + 0: + _should_follow = false + _has_multiple_follow_targets = false + 1: + _should_follow = true + _has_multiple_follow_targets = false + _: + _should_follow = true + _has_multiple_follow_targets = true + + +func _noise_emitted(emitter_noise_output: Transform2D, emitter_layer: int) -> void: + if noise_emitter_layer & emitter_layer != 0: + noise_emitted.emit(emitter_noise_output) + + +func _set_layer(current_layers: int, layer_number: int, value: bool) -> int: + var mask: int = current_layers + + # From https://github.com/godotengine/godot/blob/51991e20143a39e9ef0107163eaf283ca0a761ea/scene/3d/camera_3d.cpp#L638 + if layer_number < 1 or layer_number > 20: + printerr("Render layer must be between 1 and 20.") + else: + if value: + mask |= 1 << (layer_number - 1) + else: + mask &= ~(1 << (layer_number - 1)) + + return mask + + +func _check_physics_body(target: Node2D) -> void: + if target is PhysicsBody2D: + var show_jitter_tips := ProjectSettings.get_setting("phantom_camera/tips/show_jitter_tips") + var physics_interpolation_enabled := ProjectSettings.get_setting("physics/common/physics_interpolation") + + ## NOTE - Feature Toggle + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor < 3: + if show_jitter_tips == null: # Default value is null when referencing custom Project Setting + print_rich("Following a [b]PhysicsBody2D[/b] node will likely result in jitter - on lower physics ticks in particular.") + print_rich("If possible, will recommend upgrading to Godot 4.3, as it has built-in support for 2D Physics Interpolation, which will mitigate this issue.") + print_rich("Otherwise, try following the guide on the [url=https://phantom-camera.dev/support/faq#i-m-seeing-jitter-what-can-i-do]documentation site[/url] for better results.") + print_rich("This tip can be disabled from within [code]Project Settings / Phantom Camera / Tips / Show Jitter Tips[/code]") + return + ## NOTE - Only supported in Godot 4.3 or above + elif not physics_interpolation_enabled and show_jitter_tips == null: # Default value is null when referencing custom Project Setting + printerr("Physics Interpolation is disabled in the Project Settings, recommend enabling it to smooth out physics-based camera movement") + print_rich("This tip can be disabled from within [code]Project Settings / Phantom Camera / Tips / Show Jitter Tips[/code]") + _follow_target_physics_based = true + else: + _is_parents_physics(target) + physics_target_changed.emit() + + +func _is_parents_physics(target: Node = self) -> void: + var current_node: Node = target + while current_node: + current_node = current_node.get_parent() + if not current_node is PhysicsBody2D: continue + _follow_target_physics_based = true + +#endregion + + +#region Public Functions + +## Updates the limit sides based what has been set to define it +## This should be automatic, but can be called manully if need be. +func update_limit_all_sides() -> void: + var limit_rect: Rect2 + + if not is_instance_valid(_limit_node): + _limit_sides.x = limit_left + _limit_sides.y = limit_top + _limit_sides.z = limit_right + _limit_sides.w = limit_bottom + elif _limit_node is TileMap or _limit_node.is_class("TileMapLayer"): + var tile_map := _limit_node + + if not tile_map.tile_set: return # TODO: This should be removed once https://github.com/godotengine/godot/issues/96898 is resolved + + var tile_map_size: Vector2 = Vector2(tile_map.get_used_rect().size) * Vector2(tile_map.tile_set.tile_size) * tile_map.get_scale() + var tile_map_position: Vector2 = tile_map.global_position + Vector2(tile_map.get_used_rect().position) * Vector2(tile_map.tile_set.tile_size) * tile_map.get_scale() + + ## Calculates the Rect2 based on the Tile Map position and size + margin + limit_rect = Rect2( + tile_map_position + Vector2(limit_margin.x, limit_margin.y), + tile_map_size - Vector2(limit_margin.x, limit_margin.y) - Vector2(limit_margin.z, limit_margin.w) + ) + + # Left + _limit_sides.x = roundi(limit_rect.position.x) + # Top + _limit_sides.y = roundi(limit_rect.position.y) + # Right + _limit_sides.z = roundi(limit_rect.position.x + limit_rect.size.x) + # Bottom + _limit_sides.w = roundi(limit_rect.position.y + limit_rect.size.y) + elif _limit_node is CollisionShape2D: + var collision_shape_2d: CollisionShape2D = _limit_node as CollisionShape2D + + if not collision_shape_2d.get_shape(): return + + var shape_2d: Shape2D = collision_shape_2d.get_shape() + var shape_2d_size: Vector2 = shape_2d.get_rect().size + var shape_2d_position: Vector2 = collision_shape_2d.global_position + Vector2(shape_2d.get_rect().position) + + ## Calculates the Rect2 based on the Tile Map position and size + limit_rect = Rect2(shape_2d_position, shape_2d_size) + + ## Calculates the Rect2 based on the Tile Map position and size + margin + limit_rect = Rect2( + limit_rect.position + Vector2(limit_margin.x, limit_margin.y), + limit_rect.size - Vector2(limit_margin.x, limit_margin.y) - Vector2(limit_margin.z, limit_margin.w) + ) + + # Left + _limit_sides.x = roundi(limit_rect.position.x) + # Top + _limit_sides.y = roundi(limit_rect.position.y) + # Right + _limit_sides.z = roundi(limit_rect.position.x + limit_rect.size.x) + # Bottom + _limit_sides.w = roundi(limit_rect.position.y + limit_rect.size.y) + + _check_limit_is_not_default() + if not _is_active: return + if not is_instance_valid(_phantom_camera_manager): return + _phantom_camera_manager.limit_2d_changed.emit(SIDE_LEFT, _limit_sides.x) + _phantom_camera_manager.limit_2d_changed.emit(SIDE_TOP, _limit_sides.y) + _phantom_camera_manager.limit_2d_changed.emit(SIDE_RIGHT, _limit_sides.z) + _phantom_camera_manager.limit_2d_changed.emit(SIDE_BOTTOM, _limit_sides.w) + _phantom_camera_manager.draw_limit_2d.emit(draw_limits) + + +func reset_limit() -> void: + if not is_instance_valid(_phantom_camera_manager): return + _phantom_camera_manager.limit_2d_changed.emit(SIDE_LEFT, _limit_sides_default.x) + _phantom_camera_manager.limit_2d_changed.emit(SIDE_TOP, _limit_sides_default.y) + _phantom_camera_manager.limit_2d_changed.emit(SIDE_RIGHT, _limit_sides_default.z) + _phantom_camera_manager.limit_2d_changed.emit(SIDE_BOTTOM, _limit_sides_default.w) + _phantom_camera_manager.draw_limit_2d.emit(draw_limits) + + +## Assigns the value of the [param has_tweened] property. +## [b][color=yellow]Important:[/color][/b] This value can only be changed +## from the [PhantomCameraHost] script. +func set_tween_skip(caller: Node, value: bool) -> void: + if is_instance_of(caller, PhantomCameraHost): + _tween_skip = value + else: + printerr("Can only be called PhantomCameraHost class") +## Returns the current [param has_tweened] value. +func get_tween_skip() -> bool: + return _tween_skip + +## Returns the [Transform3D] value based on the [member follow_mode] / [member look_at_mode] target value. +func get_transform_output() -> Transform2D: + return _transform_output + + +## Returns the noise [Transform3D] value. +func get_noise_transform() -> Transform2D: + return _transform_noise + + +## Emits a noise based on a custom [Transform2D] value.[br] +## Use this function if you wish to make use of external noise patterns from, for example, other addons. +func emit_noise(value: Transform2D) -> void: + noise_emitted.emit(value) + + +## Teleports the [param PhantomCamera2D] and [Camera2D] to their designated position, +## bypassing the damping process. +func teleport_position() -> void: + _follow_velocity_ref = Vector2.ZERO + _set_follow_position() + _transform_output.origin = _follow_target_position + _phantom_camera_manager.pcam_teleport.emit(self) + + +# TODO: Enum link does link to anywhere is being tracked in: https://github.com/godotengine/godot/issues/106828 +## Returns true if this [param PhantomCamera2D]'s [member follow_mode] is not set to [enum FollowMode] +## and has a valid [member follow_target]. +func is_following() -> bool: + return _should_follow + +#endregion + + +#region Setter & Getter Functions + +## Assigns new Zoom value. +func set_zoom(value: Vector2) -> void: + zoom = value + queue_redraw() + +## Gets current Zoom value. +func get_zoom() -> Vector2: + return zoom + + +## Assigns new Priority value. +func set_priority(value: int) -> void: + priority = abs(value) + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).pcam_priority_changed.emit(self) + +## Gets current Priority value. +func get_priority() -> int: + return priority + + +## Assigns a new PhantomCameraTween resource to the PhantomCamera2D +func set_tween_resource(value: PhantomCameraTween) -> void: + tween_resource = value + +## Gets the PhantomCameraTween resource assigned to the PhantomCamera2D +## Returns null if there's nothing assigned to it. +func get_tween_resource() -> PhantomCameraTween: + return tween_resource + + +## Assigns a new [param Tween Duration] to the [member tween_resource] value.[br] +## The duration value is in seconds. +func set_tween_duration(value: float) -> void: + tween_resource.duration = value + +## Gets the current [param Tween Duration] value inside the +## [member tween_resource].[br] +## The duration value is in seconds. +func get_tween_duration() -> float: + return tween_resource.duration + + +## Assigns a new [param Tween Transition] value inside the +## [member tween_resource]. +func set_tween_transition(value: int) -> void: + tween_resource.transition = value + +## Gets the current [param Tween Transition] value inside the +## [member tween_resource]. +func get_tween_transition() -> int: + return tween_resource.transition + + +## Assigns a new [param Tween Ease] value inside the [member tween_resource]. +func set_tween_ease(value: int) -> void: + tween_resource.ease = value + +## Gets the current [param Tween Ease] value inside the [member tween_resource]. +func get_tween_ease() -> int: + return tween_resource.ease + + +## Sets the [param PhantomCamera2D] active state.[br] +## [b][color=yellow]Important:[/color][/b] This value can only be changed +## from the [PhantomCameraHost] script. +func set_is_active(node, value) -> void: + if node is PhantomCameraHost: + _is_active = value + if value: + _should_follow_checker() + queue_redraw() + else: + printerr("PCams can only be set from the PhantomCameraHost") + +## Gets current active state of the [param PhantomCamera2D]. +## If it returns true, it means the [param PhantomCamera2D] is what the +## [param Camera2D] is currently following. +func is_active() -> bool: + return _is_active + + +## Enables or disables the [member tween_on_load]. +func set_tween_on_load(value: bool) -> void: + tween_on_load = value + +## Gets the current [member tween_on_load] value. +func get_tween_on_load() -> bool: + return tween_on_load + +## Sets the [member host_layers] value. +func set_host_layers(value: int) -> void: + host_layers = value + if is_instance_valid(_phantom_camera_manager): + _phantom_camera_manager.pcam_host_layer_changed.emit(self) + +## Enables or disables a given layer of [member host_layers]. +func set_host_layers_value(layer: int, value: bool) -> void: + host_layers = _set_layer(host_layers, layer, value) + +## Gets the current [member host_layers]. +func get_host_layers() -> int: + return host_layers + + +## Gets the current follow mode as an enum int based on [enum FollowMode].[br] +## [b]Note:[/b] Setting [enum FollowMode] purposely not added. +## A separate PCam should be used instead. +func get_follow_mode() -> int: + return follow_mode + + +## Assigns a new [Node2D] as the [member follow_target]. +func set_follow_target(value: Node2D) -> void: + if follow_mode == FollowMode.NONE or follow_mode == FollowMode.GROUP: return + if follow_target == value: return + follow_target = value + _follow_target_physics_based = false + if is_instance_valid(value): + if follow_mode == FollowMode.PATH: + if is_instance_valid(follow_path): + _should_follow = true + else: + _should_follow = false + else: + _should_follow = true + _check_physics_body(value) + if not follow_target.tree_exiting.is_connected(_follow_target_tree_exiting): + follow_target.tree_exiting.connect(_follow_target_tree_exiting.bind(follow_target)) + else: + _should_follow = false + follow_target_changed.emit() + notify_property_list_changed() + +## Erases the current [member follow_target]. +func erase_follow_target() -> void: + if follow_target == null: return + _should_follow = false + follow_target = null + _follow_target_physics_based = false + follow_target_changed.emit() + +## Gets the current [member follow_target]. +func get_follow_target() -> Node2D: + return follow_target + + +## Assigns a new [Path2D] to the [member follow_path]. +func set_follow_path(value: Path2D) -> void: + follow_path = value + if is_instance_valid(follow_path): + _should_follow_checker() + else: + _should_follow = false + +## Erases the current [Path2D] from the [member follow_path] property. +func erase_follow_path() -> void: + follow_path = null + +## Gets the current [Path2D] from the [member follow_path]. +func get_follow_path() -> Path2D: + return follow_path + + +## Assigns a new [param follow_targets] array value. +func set_follow_targets(value: Array[Node2D]) -> void: + if follow_mode != FollowMode.GROUP: return + if follow_targets == value: return + follow_targets = value + _follow_targets_size_check() + +## Appends a single [Node2D] to [member follow_targets]. +func append_follow_targets(value: Node2D) -> void: + if not is_instance_valid(value): + printerr(value, " is not a valid Node2D instance") + return + + if not follow_targets.has(value): + follow_targets.append(value) + _follow_targets_size_check() + else: + printerr(value, " is already part of Follow Group") + +## Adds an Array of type [Node2D] to [member follow_targets]. +func append_follow_targets_array(value: Array[Node2D]) -> void: + for target in value: + if not is_instance_valid(target): continue + if not follow_targets.has(target): + follow_targets.append(target) + _follow_targets_size_check() + else: + printerr(value, " is already part of Follow Group") + +## Removes a [Node2D] from [member follow_targets] array. +func erase_follow_targets(value: Node2D) -> void: + follow_targets.erase(value) + _follow_targets_size_check() + +## Gets all [Node2D] from [member follow_targets] array. +func get_follow_targets() -> Array[Node2D]: + return follow_targets + + +## Assigns a new Vector2 for the Follow Target Offset property. +func set_follow_offset(value: Vector2) -> void: + var temp_offset: Vector2 = follow_offset + + follow_offset = value + + if follow_axis_lock != FollowLockAxis.NONE: + temp_offset = temp_offset - value + match value: + FollowLockAxis.X: + _follow_axis_lock_value.x = _transform_output.origin.x + temp_offset.x + FollowLockAxis.Y: + _follow_axis_lock_value.y = _transform_output.origin.y + temp_offset.y + FollowLockAxis.XY: + _follow_axis_lock_value.x = _transform_output.origin.x + temp_offset.x + _follow_axis_lock_value.y = _transform_output.origin.y + temp_offset.y + + +## Gets the current Vector2 for the Follow Target Offset property. +func get_follow_offset() -> Vector2: + return follow_offset + + +## Enables or disables Follow Damping. +func set_follow_damping(value: bool) -> void: + follow_damping = value + notify_property_list_changed() + +## Gets the current Follow Damping property. +func get_follow_damping() -> bool: + return follow_damping + + +## Assigns new Damping value. +func set_follow_damping_value(value: Vector2) -> void: + ## TODO - Should be using @export_range once minimum version support is Godot 4.3 + if value.x < 0: value.x = 0 + elif value.y < 0: value.y = 0 + follow_damping_value = value + +## Gets the current Follow Damping value. +func get_follow_damping_value() -> Vector2: + return follow_damping_value + +## Assigns a new [member follow_axis] member. Value is based on [enum FollowLockAxis] enum. +func set_lock_axis(value: FollowLockAxis) -> void: + follow_axis_lock = value + + # Wait for the node to be ready before setting lock + if not is_node_ready(): await ready + + # Prevent axis lock from working in the editor + if value != FollowLockAxis.NONE and not Engine.is_editor_hint(): + _follow_axis_is_locked = true + match value: + FollowLockAxis.X: + _follow_axis_lock_value.x = _transform_output.origin.x + FollowLockAxis.Y: + _follow_axis_lock_value.y = _transform_output.origin.y + FollowLockAxis.XY: + _follow_axis_lock_value.x = _transform_output.origin.x + _follow_axis_lock_value.y = _transform_output.origin.y + else: + _follow_axis_is_locked = false + +## Gets the current [member follow_axis_lock] value. Value is based on [enum FollowLockAxis] enum. +func get_lock_axis() -> FollowLockAxis: + return follow_axis_lock + + +## Enables or disables [member snap_to_pixel]. +func set_snap_to_pixel(value: bool) -> void: + snap_to_pixel = value + +## Gets the current [member snap_to_pixel] value. +func get_snap_to_pixel() -> bool: + return snap_to_pixel + + +## Enables or disables Auto zoom when using Group Follow. +func set_auto_zoom(value: bool) -> void: + auto_zoom = value + notify_property_list_changed() + +## Gets Auto Zoom state. +func get_auto_zoom() -> bool: + return auto_zoom + + +## Assigns new Min Auto Zoom value. +func set_auto_zoom_min(value: float) -> void: + auto_zoom_min = value + +## Gets Min Auto Zoom value. +func get_auto_zoom_min() -> float: + return auto_zoom_min + + +## Assigns new Max Auto Zoom value. +func set_auto_zoom_max(value: float) -> void: + auto_zoom_max = value + +## Gets Max Auto Zoom value. +func get_auto_zoom_max() -> float: + return auto_zoom_max + + +## Assigns new Zoom Auto Margin value. +func set_auto_zoom_margin(value: Vector4) -> void: + auto_zoom_margin = value + +## Gets Zoom Auto Margin value. +func get_auto_zoom_margin() -> Vector4: + return auto_zoom_margin + + +## Sets a limit side based on the side parameter.[br] +## It's recommended to pass the [enum Side] enum as the sid parameter. +func set_limit(side: int, value: int) -> void: + match side: + SIDE_LEFT: limit_left = value + SIDE_TOP: limit_top = value + SIDE_RIGHT: limit_right = value + SIDE_BOTTOM: limit_bottom = value + _: printerr("Not a valid Side.") + +## Gets the limit side +func get_limit(value: int) -> int: + match value: + SIDE_LEFT: return limit_left + SIDE_TOP: return limit_top + SIDE_RIGHT: return limit_right + SIDE_BOTTOM: return limit_bottom + _: + printerr("Not a valid Side.") + return -1 + + +## Assign a the Camera2D Left Limit Side value. +func set_limit_left(value: int) -> void: + _limit_target_exist_error() + limit_left = value + update_limit_all_sides() + +## Gets the Camera2D Left Limit value. +func get_limit_left() -> int: + return limit_left + + +## Assign a the Camera2D Top Limit Side value. +func set_limit_top(value: int) -> void: + _limit_target_exist_error() + limit_top = value + update_limit_all_sides() + +## Gets the Camera2D Top Limit value. +func get_limit_top() -> int: + return limit_top + + +## Assign a the Camera2D Right Limit Side value. +func set_limit_right(value: int) -> void: + _limit_target_exist_error() + limit_right = value + update_limit_all_sides() + +## Gets the Camera2D Right Limit value. +func get_limit_right() -> int: + return limit_right + + +## Assign a the Camera2D Bottom Limit Side value. +func set_limit_bottom(value: int) -> void: + _limit_target_exist_error() + limit_bottom = value + update_limit_all_sides() + +## Gets the Camera2D Bottom Limit value. +func get_limit_bottom() -> int: + return limit_bottom + + +func _limit_target_exist_error() -> void: + if not limit_target.is_empty(): + printerr("Unable to set Limit Side due to Limit Target ", _limit_node.name, " being assigned") + + +# Sets a [memeber limit_target] node. +func set_limit_target(value: NodePath) -> void: + limit_target = value + + # Waits for PCam2d's _ready() before trying to validate limit_node_path + if not is_node_ready(): await ready + + # Removes signal from existing TileMap node + if is_instance_valid(get_node_or_null(value)): + var prev_limit_node: Node2D = _limit_node + var new_limit_node: Node2D = get_node(value) + + if prev_limit_node: + if prev_limit_node is TileMap or prev_limit_node.is_class("TileMapLayer"): + if prev_limit_node.changed.is_connected(_on_tile_map_changed): + prev_limit_node.changed.disconnect(_on_tile_map_changed) + + if new_limit_node is TileMap or new_limit_node.is_class("TileMapLayer"): + if not new_limit_node.changed.is_connected(_on_tile_map_changed): + new_limit_node.changed.connect(_on_tile_map_changed) + elif new_limit_node is CollisionShape2D: + var col_shape: CollisionShape2D = get_node(value) + + if col_shape.shape == null: + printerr("No Shape2D in: ", col_shape.name) + reset_limit() + limit_target = "" + return + else: + printerr("Limit Target is not a TileMap, TileMapLayer or CollisionShape2D node") + return + elif value == NodePath(""): + reset_limit() + limit_target = "" + else: + printerr("Limit Target cannot be found") + return + + _limit_node = get_node_or_null(value) + + notify_property_list_changed() + update_limit_all_sides() + +## Get [member limit_target] node. +func get_limit_target() -> NodePath: + if not limit_target: # TODO - Fixes an spam error if if limit_taret is empty + return NodePath("") + else: + return limit_target + + +## Set Tile Map Limit Margin. +func set_limit_margin(value: Vector4i) -> void: + limit_margin = value + update_limit_all_sides() +## Get Tile Map Limit Margin. +func get_limit_margin() -> Vector4i: + return limit_margin + + +### Enables or disables the Limit Smoothing beaviour. +#func set_limit_smoothing(value: bool) -> void: + #limit_smoothed = value +### Returns the Limit Smoothing beaviour. +#func get_limit_smoothing() -> bool: + #return limit_smoothed + + +## Sets a [PhantomCameraNoise2D] resource. +func set_noise(value: PhantomCameraNoise2D) -> void: + noise = value + if value != null: + _has_noise_resource = true + noise.set_trauma(1) + else: + _has_noise_resource = false + _transform_noise = Transform2D() + +## Returns the [PhantomCameraNoise2D] resource. +func get_noise() -> PhantomCameraNoise2D: + return noise + +func has_noise_resource() -> bool: + return _has_noise_resource + + +## Sets the [member noise_emitter_layer] value. +func set_noise_emitter_layer(value: int) -> void: + noise_emitter_layer = value + +## Enables or disables a given layer of [member noise_emitter_layer]. +func set_noise_emitter_layer_value(value: int, enabled: bool) -> void: + noise_emitter_layer = _set_layer(noise_emitter_layer, value, enabled) + +## Returns the [member noise_emitter_layer] +func get_noise_emitter_layer() -> int: + return noise_emitter_layer + + +## Sets [member inactive_update_mode] property. +func set_inactive_update_mode(value: int) -> void: + inactive_update_mode = value + +## Gets [enum InactiveUpdateMode] value. +func get_inactive_update_mode() -> int: + return inactive_update_mode + + +func get_follow_target_physics_based() -> bool: + return _follow_target_physics_based + + +func get_class() -> String: + return "PhantomCamera2D" + + +func is_class(value) -> bool: + return value == "PhantomCamera2D" + +#endregion diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd new file mode 100644 index 0000000..fdec408 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd @@ -0,0 +1,2229 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_3d.svg") +class_name PhantomCamera3D +extends Node3D + +## Controls a scene's [Camera3D] and applies logic to it. +## +## The scene's [Camera3D] will follow the position of the +## [param PhantomCamera3D] with the highest priority. +## Each instance can have different positional and rotational logic applied +## to them. + +#region Constants + +const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +#endregion + +#region Signals + +## Emitted when the [param PhantomCamera3D] becomes active. +signal became_active + +## Emitted when the [param PhantomCamera3D] becomes inactive. +signal became_inactive + +## Emitted when the follow_mode changes. +## Note: This is for internal use only +signal follow_mode_changed + +## Emitted when [member follow_target] changes. +signal follow_target_changed + +## Emitted when [member look_at_target] changes. +signal look_at_target_changed + +## Emitted when dead zones changes.[br] +## [b]Note:[/b] Only applicable in [param Framed] [member FollowMode]. +signal dead_zone_changed + +## Emitted when a target touches the edge of the dead zone in [param Framed] [enum FollowMode]. +signal dead_zone_reached + +## Emitted when the [param Camera3D] starts to tween to another +## [param PhantomCamera3D]. +signal tween_started + +## Emitted when the [param Camera3D] is to tweening towards another +## [param PhantomCamera3D]. +signal is_tweening + +## Emitted when the tween is interrupted due to another [param PhantomCamera3D] +## becoming active. The argument is the [param PhantomCamera3D] that +## interrupted the tween. +signal tween_interrupted(pcam_3d: PhantomCamera3D) + +## Emitted when the [param Camera3D] completes its tween to the +## [param PhantomCamera3D]. +signal tween_completed + +## Emitted when Noise should be applied to the [param Camera3D]. +signal noise_emitted(noise_output: Transform3D) + +signal physics_target_changed + +signal camera_3d_resource_property_changed(property: StringName, value: Variant) +signal camera_3d_resource_changed + +#endregion + + +#region Enums + +## Determines the positional logic for a given [param PhantomCamera3D] +## [br][br] +## The different modes have different functionalities and purposes, so choosing +## the correct one depends on what each [param PhantomCamera3D] is meant to do. +enum FollowMode { + NONE = 0, ## Default - No follow logic is applied. + GLUED = 1, ## Sticks to its target. + SIMPLE = 2, ## Follows its target with an optional offset. + GROUP = 3, ## Follows multiple targets with option to dynamically reframe itself. + PATH = 4, ## Follows a target while being positionally confined to a [Path3D] node. + FRAMED = 5, ## Applies a dead zone on the frame and only follows its target when it tries to leave it. + THIRD_PERSON = 6, ## Applies a [SpringArm3D] node to the target's position and allows for rotating around it. +} + +## Determines the rotational logic for a given [param PhantomCamera3D].[br][br] +## The different modes has different functionalities and purposes, so +## choosing the correct mode depends on what each [param PhantomCamera3D] +## is meant to do. +enum LookAtMode { + NONE = 0, ## Default - No Look At logic is applied. + MIMIC = 1, ## Copies its target's rotational value. + SIMPLE = 2, ## Looks at its target in a straight line. + GROUP = 3, ## Looks at the centre of its targets. +} + +## Determines how often an inactive [param PhantomCamera3D] should update +## its positional and rotational values. This is meant to reduce the amount +## of calculations inactive [param PhantomCamera3D] are doing when idling +## to improve performance. +enum InactiveUpdateMode { + ALWAYS, ## Always updates the [param PhantomCamera3D], even when it's inactive. + NEVER, ## Never updates the [param PhantomCamera3D] when it's inactive. Reduces the amount of computational resources when inactive. +# EXPONENTIALLY, +} + +enum FollowLockAxis { + NONE = 0, + X = 1, + Y = 2, + Z = 3, + XY = 4, + XZ = 5, + YZ = 6, + XYZ = 7, +} + +#endregion + + +#region Exported Properties + +## To quickly preview a [param PhantomCamera3D] without adjusting its +## [member Priority], this property allows the selected [param PhantomCamera3D] +## to ignore the Priority system altogether and forcefully become the active +## one. It's partly designed to work within the [param viewfinder], and will be +## disabled when running a build export of the game. +@export var priority_override: bool = false: + set(value): + priority_override = value + if Engine.is_editor_hint(): + if value: + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).pcam_priority_override.emit(self, priority_override) + else: + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).pcam_priority_override.emit(self, priority_override) + get: + return priority_override + + +## It defines which [param PhantomCamera3D] a scene's [param Camera3D] should +## be corresponding with and be attached to. This is decided by the +## [param PhantomCamera3D] with the highest [param priority]. +## [br][br] +## Changing [param priority] will send an event to the scene's +## [PhantomCameraHost], which will then determine whether if the +## [param priority] value is greater than or equal to the currently +## highest [param PhantomCamera3D]'s in the scene. The +## [param PhantomCamera3D] with the highest value will then reattach the +## Camera accordingly. +@export var priority: int = 0: + set = set_priority, + get = get_priority + + +## Determines the positional logic for a given [param PhantomCamera3D]. +## The different modes have different functionalities and purposes, so +## choosing the correct one depends on what each [param PhantomCamera3D] +## is meant to do. +@export var follow_mode: FollowMode = FollowMode.NONE: + set(value): + follow_mode = value + + if follow_mode == FollowMode.NONE: + _should_follow = false + top_level = false + _is_parents_physics() + notify_property_list_changed() + return + + match follow_mode: + FollowMode.PATH: + if is_instance_valid(follow_path): + _should_follow_checker() + FollowMode.GROUP: + _follow_targets_size_check() + _: + _should_follow_checker() + + if follow_mode == FollowMode.FRAMED: + if _follow_framed_initial_set and follow_target: + _follow_framed_initial_set = false + dead_zone_changed.connect(_on_dead_zone_changed) + else: + if dead_zone_changed.is_connected(_on_dead_zone_changed): + dead_zone_changed.disconnect(_on_dead_zone_changed) + + if follow_mode == FollowMode.THIRD_PERSON: + top_level = false + _is_third_person_follow = true + else: + top_level = true + _is_third_person_follow = false + + follow_mode_changed.emit() + notify_property_list_changed() + + ## NOTE - Warning that Look At + Follow Mode hasn't been fully tested together yet + if look_at_mode != LookAtMode.NONE: + print_rich("[color=#EAA15E]Warning: Using both Look At and Follow Mode on the same PCam3D has not been fully tested yet, proceed with caution![/color]") + get: + return follow_mode + +## Determines which target should be followed. +## The [param Camera3D] will follow the position of the Follow Target based on +## the [member follow_mode] type and its parameters. +@export var follow_target: Node3D = null: + set = set_follow_target, + get = get_follow_target + +## Defines the targets that the [param PhantomCamera3D] should be following. +@export var follow_targets: Array[Node3D] = []: + set = set_follow_targets, + get = get_follow_targets + +## Determines the [Path3D] node the [param PhantomCamera3D] +## should be bound to. +## The [param PhantomCamera3D] will follow the position of the +## [member follow_target] while sticking to the closest point on this path. +@export var follow_path: Path3D = null: + set = set_follow_path, + get = get_follow_path + + +## Determines the rotational logic for a given [param PhantomCamera3D]. +## The different modes has different functionalities and purposes, +## so choosing the correct mode depends on what each +## [param PhantomCamera3D] is meant to do. +@export var look_at_mode: LookAtMode = LookAtMode.NONE: + set(value): + look_at_mode = value + + if look_at_mode == LookAtMode.NONE: + _should_look_at = false + notify_property_list_changed() + return + + if not look_at_mode == LookAtMode.GROUP: + if look_at_target is Node3D: + _should_look_at = true + else: # If Look At Group + _look_at_targets_size_check() + notify_property_list_changed() + + ## NOTE - Warning that Look At + Follow Mode hasn't been fully tested together yet + if follow_mode != FollowMode.NONE: + print_rich("[color=#EAA15E]Warning: Using both Look At and Follow Mode on the same PCam3D has not been fully tested yet, proceed with caution![/color]") + get: + return look_at_mode + +## Determines which target should be looked at. +## The [param PhantomCamera3D] will update its rotational value as the +## target changes its position. +@export var look_at_target: Node3D = null: + set = set_look_at_target, + get = get_look_at_target + +## Defines the targets that the camera should looking at. +## It will be looking at the centre of all the assigned targets. +@export var look_at_targets: Array[Node3D] = []: + set = set_look_at_targets, + get = get_look_at_targets + + +## Defines how [param ]PhantomCamera3Ds] transition between one another. +## Changing the tween values for a given [param PhantomCamera3D] +## determines how transitioning to that instance will look like. +## This is a resource type that can be either used for one +## [param PhantomCamera] or reused across multiple - both 2D and 3D. +## By default, all [param PhantomCameras] will use a [param linear] +## transition, [param easeInOut] ease with a [param 1s] duration. +@export var tween_resource: PhantomCameraTween = PhantomCameraTween.new(): + set = set_tween_resource, + get = get_tween_resource + +## If enabled, the moment a [param PhantomCamera3D] is instantiated into +## a scene, and has the highest priority, it will perform its tween transition. +## This is most obvious if a [param PhantomCamera3D] has a long duration and +## is attached to a playable character that can be moved the moment a scene +## is loaded. Disabling the [param tween_on_load] property will +## disable this behaviour and skip the tweening entirely when instantiated. +@export var tween_on_load: bool = true: + set = set_tween_on_load, + get = get_tween_on_load + + +## Determines how often an inactive [param PhantomCamera3D] should update +## its positional and rotational values. This is meant to reduce the amount +## of calculations inactive [param PhantomCamera3Ds] are doing when idling +## to improve performance. +@export var inactive_update_mode: InactiveUpdateMode = InactiveUpdateMode.ALWAYS: + set = set_inactive_update_mode, + get = get_inactive_update_mode + + +## Determines which layers this [param PhantomCamera3D] should be able to communicate with [PhantomCameraHost] nodes.[br] +## A corresponding layer needs to be set on the [PhantomCameraHost] node. +@export_flags_3d_render var host_layers: int = 1: + set = set_host_layers, + get = get_host_layers + + +## A resource type that allows for overriding the [param Camera3D] node's +## properties. +@export var camera_3d_resource: Camera3DResource = null: + set = set_camera_3d_resource, + get = get_camera_3d_resource + + +## Overrides the [member Camera3D.attribuets] resource property. +@export var attributes: CameraAttributes = null: + set = set_attributes, + get = get_attributes + + +## Overrides the [member Camera3D.environment] resource property. +@export var environment: Environment = null: + set = set_environment, + get = get_environment + + +@export_group("Follow Parameters") +## Offsets the [member follow_target] position. +@export var follow_offset: Vector3 = Vector3.ZERO: + set = set_follow_offset, + get = get_follow_offset + +## Applies a damping effect on the camera's movement. +## Leading to heavier / slower camera movement as the targeted node moves around. +## This is useful to avoid sharp and rapid camera movement. +@export var follow_damping: bool = false: + set = set_follow_damping, + get = get_follow_damping + +## Defines the damping amount. The ideal range should be somewhere between 0-1.[br][br] +## The damping amount can be specified in the individual axis.[br][br] +## [b]Lower value[/b] = faster / sharper camera movement.[br] +## [b]Higher value[/b] = slower / heavier camera movement. +@export var follow_damping_value: Vector3 = Vector3(0.1, 0.1, 0.1): + set = set_follow_damping_value, + get = get_follow_damping_value + + +## Prevents the [param PhantomCamera2D] from moving in a designated axis. +## This can be enabled or disabled at runtime or from the editor directly. +@export var follow_axis_lock: FollowLockAxis = FollowLockAxis.NONE: + set = set_follow_axis_lock, + get = get_follow_axis_lock +var _follow_axis_is_locked: bool = false +var _follow_axis_lock_value: Vector3 = Vector3.ZERO + + +## Sets a distance offset from the centre of the target's position. +## The distance is applied to the [param PhantomCamera3D]'s local z axis. +@export var follow_distance: float = 1: + set = set_follow_distance, + get = get_follow_distance + +## Enables the [param PhantomCamera3D] to automatically distance +## itself as the [param follow targets] move further apart.[br] +## It looks at the longest axis between the different targets and interpolates +## the distance length between the [member auto_follow_distance_min] and +## [member follow_group_distance] properties.[br][br] +## Note: Enabling this property hides and disables the [member follow_distance] +## property as this effectively overrides that property. +@export var auto_follow_distance: bool = false: + set = set_auto_follow_distance, + get = get_auto_follow_distance + +## Sets the minimum distance between the Camera and centre of [AABB]. +## [br][br] +## Note: This distance will only ever be reached when all the targets are in +## the exact same [param Vector3] coordinate, which will very unlikely +## happen, so adjust the value here accordingly. +## [br][br] +## If only one follow target is assigned to [member follow_targets], this value will be used as the `follow_distance`. +@export var auto_follow_distance_min: float = 1: + set = set_auto_follow_distance_min, + get = get_auto_follow_distance_min + +## Sets the maximum distance between the Camera and centre of [AABB]. +@export var auto_follow_distance_max: float = 5: + set = set_auto_follow_distance_max, + get = get_auto_follow_distance_max + +## Determines how fast the [member auto_follow_distance] moves between the +## maximum and minimum distance. The higher the value, the sooner the +## maximum distance is reached.[br][br] +## This value should be based on the sizes of the [member auto_follow_distance_min] +## and [member auto_follow_distance_max].[br] +## E.g. if the value between the [member auto_follow_distance_min] and +## [member auto_follow_distance_max] is small, consider keeping the number low +## and vice versa. +@export var auto_follow_distance_divisor: float = 10: + set = set_auto_follow_distance_divisor, + get = get_auto_follow_distance_divisor + + +@export_subgroup("Dead Zones") +## Defines the horizontal dead zone area. While the target is within it, the +## [param PhantomCamera3D] will not move in the horizontal axis. +## If the targeted node leaves the horizontal bounds, the +## [param PhantomCamera3D] will follow the target horizontally to keep +## it within bounds. +@export_range(0, 1) var dead_zone_width: float = 0: + set(value): + dead_zone_width = value + dead_zone_changed.emit() + get: + return dead_zone_width + +## Defines the vertical dead zone area. While the target is within it, the +## [param PhantomCamera3D] will not move in the vertical axis. +## If the targeted node leaves the vertical bounds, the +## [param PhantomCamera3D] will follow the target horizontally to keep +## it within bounds. +@export_range(0, 1) var dead_zone_height: float = 0: + set(value): + dead_zone_height = value + dead_zone_changed.emit() + get: + return dead_zone_height + +## Enables the dead zones to be visible when running the game from the editor. +## Dead zones will never be visible in build exports. +@export var show_viewfinder_in_play: bool = false + +## Defines the position of the [member follow_target] within the viewport.[br] +## This is only used for when [member follow_mode] is set to [param Framed]. +@export_subgroup("Spring Arm") + +## Defines the [member SpringArm3D.spring_length]. +@export var spring_length: float = 1: + set = set_spring_length, + get = get_spring_length + +## Defines the [member SpringArm3D.collision_mask] node's Collision Mask. +@export_flags_3d_physics var collision_mask: int = 1: + set = set_collision_mask, + get = get_collision_mask + +## Defines the [member SpringArm3D.shape] node's Shape3D. +@export var shape: Shape3D = null: + set = set_shape, + get = get_shape + +## Defines the [member SpringArm3D.margin] node's Margin. +@export var margin: float = 0.01: + set = set_margin, + get = get_margin + + +@export_group("Look At Parameters") +## Offsets the target's [param Vector3] position that the +## [param PhantomCamera3D] is looking at. +@export var look_at_offset: Vector3 = Vector3.ZERO: + set = set_look_at_offset, + get = get_look_at_offset + +## Applies a damping effect on the camera's rotation. +## Leading to heavier / slower camera movement as the targeted node moves around. +## This is useful to avoid sharp and rapid camera rotation. +@export var look_at_damping: bool = false: + set = set_look_at_damping, + get = get_look_at_damping + +## Defines the Rotational damping amount. The ideal range is typically somewhere between 0-1.[br][br] +## The damping amount can be specified in the individual axis.[br][br] +## [b]Lower value[/b] = faster / sharper camera rotation.[br] +## [b]Higher value[/b] = slower / heavier camera rotation. +@export_range(0.0, 1.0, 0.001, "or_greater") var look_at_damping_value: float = 0.25: + set = set_look_at_damping_value, + get = get_look_at_damping_value + +@export_subgroup("Up Direction") + +## Defines the upward direction of the [param PhantomCamera3D] when [member look_at_mode] is set. [br] +## This value will be overriden if [member up_target] is defined. +@export var up: Vector3 = Vector3.UP: + set = set_up, + get = get_up + +## Applies and continuously updates the [param up] direction of the [param PhantomCamera3D] based on this target when [member look_at_mode] is set.[br] +## Setting a value here will override the [member up] value. +@export var up_target: Node3D = null: + set = set_up_target, + get = get_up_target + + +@export_group("Noise") +## Applies a noise, or shake, to a [Camera3D].[br] +## Once set, the noise will run continuously after the tween to the [PhantomCamera3D] instance is complete. +@export var noise: PhantomCameraNoise3D = null: + set = set_noise, + get = get_noise + +## If true, will trigger the noise while in the editor.[br] +## Useful in cases where you want to temporarily disalbe the noise in the editor without removing +## the resource.[br][br] +## [b]Note:[/b] This property has no effect on runtime behaviour. +@export var _preview_noise: bool = true: + set(value): + _preview_noise = value + if not value: + _transform_noise = Transform3D() + +## Enable a corresponding layer for a [member PhantomCameraNoiseEmitter3D.noise_emitter_layer] +## to make this [PhantomCamera3D] be affect by it. +@export_flags_3d_render var noise_emitter_layer: int = 0: + set = set_noise_emitter_layer, + get = get_noise_emitter_layer + +#endregion + +#region Private Variables + +var _is_active: bool = false + +var _is_third_person_follow: bool = false +var _camera_target: Node3D = self # Calculates the position of the camera in the editor, uses instantiated SpringArm3D node when running the scene + +var _should_follow: bool = false +var _follow_target_physics_based: bool = false +var _physics_interpolation_enabled: bool = false ## TOOD - Should be enbled once toggling physics_interpolation_mode ON, when previously OFF, works in 3D + +var _has_multiple_follow_targets: bool = false +var _follow_targets_single_target_index: int = 0 +var _follow_targets: Array[Node3D] = [] + +var _should_look_at: bool = false +var _look_at_target_physics_based: bool = false + +var _has_multiple_look_at_targets: bool = false +var _look_at_targets_single_target_index: int = 0 + +var _current_rotation: Vector3 = Vector3.ZERO + +var _up: Vector3 = Vector3.UP +var _has_up_target: bool = false + +var _follow_target_position: Vector3 = Vector3.ZERO +var _look_at_target_position: Vector3 = Vector3.ZERO + +var _transform_output: Transform3D = Transform3D() +var _transform_noise: Transform3D = Transform3D() + +var _tween_skip: bool = false + +var _follow_velocity_ref: Vector3 = Vector3.ZERO # Stores and applies the velocity of the movement + +var _follow_framed_initial_set: bool = false +var _follow_framed_offset: Vector3 = Vector3.ZERO + +var _follow_spring_arm: SpringArm3D = null +var _has_follow_spring_arm: bool = false + +var _has_noise_resource: bool = false + + +# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box. +var _phantom_camera_manager: Node = null + +#endregion + +#region Public Variable + +var tween_duration: float: + set = set_tween_duration, + get = get_tween_duration +var tween_transition: PhantomCameraTween.TransitionType: + set = set_tween_transition, + get = get_tween_transition +var tween_ease: PhantomCameraTween.EaseType: + set = set_tween_ease, + get = get_tween_ease + +var keep_aspect: int: + set = set_keep_aspect, + get = get_keep_aspect +var cull_mask: int: + set = set_cull_mask, + get = get_cull_mask +var h_offset: float: + set = set_h_offset, + get = get_h_offset +var v_offset: float: + set = set_v_offset, + get = get_v_offset +var projection: Camera3DResource.ProjectionType: + set = set_projection, + get = get_projection +var fov: float: + set = set_fov, + get = get_fov +var size: float: + set = set_size, + get = get_size +var frustum_offset: Vector2: + set = set_frustum_offset, + get = get_frustum_offset +var far: float: + set = set_far, + get = get_far +var near: float: + set = set_near, + get = get_near + +var viewport_position: Vector2 + +#endregion + + +#region Private Functions + +func _validate_property(property: Dictionary) -> void: + ################ + ## Follow Target + ################ + if property.name == "follow_target": + if follow_mode == FollowMode.NONE or \ + follow_mode == FollowMode.GROUP: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_path" and \ + follow_mode != FollowMode.PATH: + property.usage = PROPERTY_USAGE_NO_EDITOR + + #################### + ## Follow Parameters + #################### + if follow_mode == FollowMode.NONE: + match property.name: + "follow_offset", \ + "follow_damping", \ + "follow_damping_value", \ + "follow_axis_lock": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_offset": + if follow_mode == FollowMode.PATH or \ + follow_mode == FollowMode.GLUED: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_damping_value" and not follow_damping: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_offset": + if follow_mode == FollowMode.PATH: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "follow_distance": + if not follow_mode == FollowMode.FRAMED: + if not follow_mode == FollowMode.GROUP or \ + auto_follow_distance: \ + property.usage = PROPERTY_USAGE_NO_EDITOR + + ############### + ## Group Follow + ############### + if property.name == "follow_targets" and \ + not follow_mode == FollowMode.GROUP: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "auto_follow_distance" and \ + not follow_mode == FollowMode.GROUP: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if not auto_follow_distance or not follow_mode == FollowMode.GROUP: + match property.name: + "auto_follow_distance_min", \ + "auto_follow_distance_max", \ + "auto_follow_distance_divisor": + property.usage = PROPERTY_USAGE_NO_EDITOR + + ############### + ## Framed Follow + ############### + if not follow_mode == FollowMode.FRAMED: + match property.name: + "dead_zone_width", \ + "dead_zone_height", \ + "show_viewfinder_in_play": + property.usage = PROPERTY_USAGE_NO_EDITOR + + ###################### + ## Third Person Follow + ###################### + if not follow_mode == FollowMode.THIRD_PERSON: + match property.name: + "spring_length", \ + "collision_mask", \ + "shape", \ + "margin": + property.usage = PROPERTY_USAGE_NO_EDITOR + + ########## + ## Look At + ########## + if look_at_mode == LookAtMode.NONE: + match property.name: + "look_at_target", \ + "look_at_offset" , \ + "look_at_damping", \ + "look_at_damping_value", \ + "up", \ + "up_target": + property.usage = PROPERTY_USAGE_NO_EDITOR + elif look_at_mode == LookAtMode.GROUP: + match property.name: + "look_at_target": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "look_at_target": + if look_at_mode == LookAtMode.NONE or \ + look_at_mode == LookAtMode.GROUP: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "look_at_targets" and \ + not look_at_mode == LookAtMode.GROUP: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "look_at_damping_value" and \ + not look_at_damping: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "up" and _has_up_target: + property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _enter_tree() -> void: + _phantom_camera_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME) + _tween_skip = !tween_on_load + + _phantom_camera_manager.pcam_added(self) + + priority_override = false + + if not visibility_changed.is_connected(_check_visibility): + visibility_changed.connect(_check_visibility) + + _should_follow_checker() + _should_look_at_checker() + + if follow_mode == FollowMode.GROUP: + _follow_targets_size_check() + elif follow_mode == FollowMode.NONE: + _is_parents_physics() + + if look_at_mode == LookAtMode.GROUP: + _look_at_targets_size_check() + + #if not get_parent() is SpringArm3D: + #if look_at_target: + #_look_at_target_node = look_at_target + #elif look_at_targets: + #_look_at_group_nodes.clear() + #for path in look_at_targets: + #if not path.is_empty() and path: + #_should_look_at = true + #_has_look_at_targets = true + #_look_at_group_nodes.append(path) + + +func _exit_tree() -> void: + if not follow_mode == FollowMode.GROUP: + follow_targets = [] + + if not is_instance_valid(_phantom_camera_manager): return + _phantom_camera_manager.pcam_removed(self) + + +func _ready(): + match follow_mode: + FollowMode.THIRD_PERSON: + _is_third_person_follow = true + if _should_follow: _transform_output.origin = _get_target_position_offset_distance() + if not Engine.is_editor_hint(): + if not is_instance_valid(_follow_spring_arm): + _follow_spring_arm = SpringArm3D.new() + _follow_spring_arm.top_level = true + _follow_spring_arm.rotation = global_rotation + _follow_spring_arm.spring_length = spring_length + _follow_spring_arm.collision_mask = collision_mask + _follow_spring_arm.shape = shape + _follow_spring_arm.margin = margin + if _should_follow: _follow_spring_arm.add_excluded_object(follow_target) + get_parent().add_child.call_deferred(_follow_spring_arm) + reparent.call_deferred(_follow_spring_arm) + + # Waits for the SpringArm3D to be ready and then apply rotation + # Resolves an issue most prominent in Godot 4.4 + await _follow_spring_arm.ready + _camera_target = _follow_spring_arm + _follow_spring_arm.global_position = _get_target_position_offset() if is_instance_valid(follow_target) else global_position + _follow_spring_arm.global_rotation = global_rotation + _has_follow_spring_arm = true + FollowMode.FRAMED: + if not Engine.is_editor_hint(): + if is_instance_valid(follow_target): + _follow_framed_offset = global_position - _get_target_position_offset() + _current_rotation = global_rotation + FollowMode.GROUP: + _follow_targets_size_check() + _: + if is_instance_valid(follow_target): + _transform_output.origin = _get_target_position_offset() + else: + _transform_output.origin = global_transform.origin + + if not Engine.is_editor_hint(): + _preview_noise = true + + ## NOTE - Only here to set position for Framed View on startup. + ## Should be removed once https://github.com/ramokz/phantom-camera/issues/161 is complete + _transform_output = global_transform + + _phantom_camera_manager.noise_3d_emitted.connect(_noise_emitted) + + +func _process(delta: float) -> void: + if _follow_target_physics_based or _is_active: return + process_logic(delta) + + +func _physics_process(delta: float) -> void: + if not _follow_target_physics_based or _is_active: return + process_logic(delta) + + +func process_logic(delta: float) -> void: + if _is_active: + if _has_noise_resource and _preview_noise: + _transform_noise = noise.get_noise_transform(delta) + else: + match inactive_update_mode: + InactiveUpdateMode.NEVER: return + # InactiveUpdateMode.EXPONENTIALLY: + # TODO - Trigger positional updates less frequently as more PCams gets added + + if _should_follow: + _follow(delta) + else: + _transform_output.origin = global_transform.origin + + if _should_look_at: + _look_at(delta) + else: + _transform_output.basis = global_basis + + if _follow_axis_is_locked: + match follow_axis_lock: + FollowLockAxis.X: + _transform_output.origin.x = _follow_axis_lock_value.x + FollowLockAxis.Y: + _transform_output.origin.y = _follow_axis_lock_value.y + FollowLockAxis.Z: + _transform_output.origin.z = _follow_axis_lock_value.z + FollowLockAxis.XY: + _transform_output.origin.x = _follow_axis_lock_value.x + _transform_output.origin.y = _follow_axis_lock_value.y + FollowLockAxis.XZ: + _transform_output.origin.x = _follow_axis_lock_value.x + _transform_output.origin.z = _follow_axis_lock_value.z + FollowLockAxis.YZ: + _transform_output.origin.y = _follow_axis_lock_value.y + _transform_output.origin.z = _follow_axis_lock_value.z + FollowLockAxis.XYZ: + _transform_output.origin.x = _follow_axis_lock_value.x + _transform_output.origin.y = _follow_axis_lock_value.y + _transform_output.origin.z = _follow_axis_lock_value.z + + +func _follow(delta: float) -> void: + _set_follow_position() + _interpolate_position(delta) + +func _look_at(delta: float) -> void: + _set_look_at_position() + _interpolate_rotation(delta) + + +func _set_follow_position() -> void: + match follow_mode: + FollowMode.GLUED: + _follow_target_position = follow_target.global_position + + FollowMode.SIMPLE: + _follow_target_position = _get_target_position_offset() + + FollowMode.GROUP: + if _has_multiple_follow_targets: + var bounds: AABB = AABB(_follow_targets[0].global_position, Vector3.ZERO) + for target in _follow_targets: + bounds = bounds.expand(target.global_position) + var distance: float + if auto_follow_distance: + distance = lerpf(auto_follow_distance_min, auto_follow_distance_max, bounds.get_longest_axis_size() / auto_follow_distance_divisor) + distance = clampf(distance, auto_follow_distance_min, auto_follow_distance_max) + else: + distance = follow_distance + + _follow_target_position = \ + bounds.get_center() + \ + follow_offset + \ + global_transform.basis.z * \ + Vector3(distance, distance, distance) + else: + _follow_target_position = \ + follow_targets[_follow_targets_single_target_index].global_position + \ + follow_offset + \ + global_transform.basis.z * \ + Vector3(auto_follow_distance_min, auto_follow_distance_min, auto_follow_distance_min) + + FollowMode.PATH: + var path_position: Vector3 = follow_path.global_position + _follow_target_position = \ + follow_path.curve.get_closest_point( + follow_target.global_position - path_position + ) + path_position + + FollowMode.FRAMED: + if not Engine.is_editor_hint(): + if not _is_active: + _follow_target_position = _get_target_position_offset_distance() + else: + viewport_position = get_viewport().get_camera_3d().unproject_position(_get_target_position_offset()) + var visible_rect_size: Vector2 = get_viewport().get_visible_rect().size + viewport_position = viewport_position / visible_rect_size + _current_rotation = global_rotation + + if _current_rotation != global_rotation: + _follow_target_position = _get_target_position_offset_distance() + + if _get_framed_side_offset() != Vector2.ZERO: + var target_position: Vector3 = _get_target_position_offset() + _follow_framed_offset + var glo_pos: Vector3 + + if dead_zone_width == 0 || dead_zone_height == 0: + if dead_zone_width == 0 && dead_zone_height != 0: + glo_pos = _get_target_position_offset_distance() + glo_pos.z = target_position.z + _follow_target_position = glo_pos + elif dead_zone_width != 0 && dead_zone_height == 0: + glo_pos = _get_target_position_offset_distance() + glo_pos.x = target_position.x + _follow_target_position = glo_pos + else: + _follow_target_position = _get_target_position_offset_distance() + else: + if _current_rotation != global_rotation: + var opposite: float = sin(-global_rotation.x) * follow_distance + _get_target_position_offset().y + glo_pos.y = _get_target_position_offset().y + opposite + glo_pos.z = sqrt(pow(follow_distance, 2) - pow(opposite, 2)) + _get_target_position_offset().z + glo_pos.x = global_position.x + + _follow_target_position = glo_pos + _current_rotation = global_rotation + else: + dead_zone_reached.emit() + _follow_target_position = target_position + else: + _follow_framed_offset = global_position - _get_target_position_offset() + _current_rotation = global_rotation + return + else: + _follow_target_position = _get_target_position_offset_distance() + var unprojected_position: Vector2 = _get_raw_unprojected_position() + var viewport_width: float = get_viewport().size.x + var viewport_height: float = get_viewport().size.y + var camera_aspect: Camera3D.KeepAspect = get_viewport().get_camera_3d().keep_aspect + var visible_rect_size: Vector2 = get_viewport().get_visible_rect().size + + unprojected_position = unprojected_position - visible_rect_size / 2 + if camera_aspect == Camera3D.KeepAspect.KEEP_HEIGHT: + # Landscape View + var aspect_ratio_scale: float = viewport_width / viewport_height + unprojected_position.x = (unprojected_position.x / aspect_ratio_scale + 1) / 2 + unprojected_position.y = (unprojected_position.y + 1) / 2 + else: + # Portrait View + var aspect_ratio_scale: float = viewport_height / viewport_width + unprojected_position.x = (unprojected_position.x + 1) / 2 + unprojected_position.y = (unprojected_position.y / aspect_ratio_scale + 1) / 2 + + viewport_position = unprojected_position + + FollowMode.THIRD_PERSON: + if not Engine.is_editor_hint(): + if not _has_follow_spring_arm: return + _follow_target_position = _get_target_position_offset() + else: + _follow_target_position = _get_target_position_offset_distance() +# _follow_target_position = _get_target_position_offset_distance_direction() + + +func _set_look_at_position() -> void: + match look_at_mode: + LookAtMode.MIMIC: + _look_at_target_position = global_position - look_at_target.global_basis.z + + LookAtMode.SIMPLE: + _look_at_target_position =look_at_target.global_position + + LookAtMode.GROUP: + if not _has_multiple_look_at_targets: + _look_at_target_position =look_at_targets[_look_at_targets_single_target_index].global_position + else: + var bounds: AABB = AABB(look_at_targets[0].global_position, Vector3.ZERO) + for node in look_at_targets: + bounds = bounds.expand(node.global_position) + _look_at_target_position =bounds.get_center() + + +func _get_target_position_offset() -> Vector3: + return follow_target.global_position + follow_offset + + +func _get_target_position_offset_distance() -> Vector3: + return _get_target_position_offset() + \ + transform.basis.z * Vector3(follow_distance, follow_distance, follow_distance) + +#func _get_target_position_offset_distance_direction() -> Vector3: +# return (_get_target_position_offset() + \ +# follow_target.global_basis.z * Vector3(follow_distance, follow_distance, follow_distance)) * Quaternion.from_euler(rotational_offset) + + +func _set_follow_velocity(index: int, value: float) -> void: + _follow_velocity_ref[index] = value + +func _interpolate_position(delta: float) -> void: + if follow_damping and not Engine.is_editor_hint(): + if not _is_third_person_follow: + global_position = _follow_target_position + for i in 3: + _transform_output.origin[i] = _smooth_damp( + global_position[i], + _transform_output.origin[i], + i, + _follow_velocity_ref[i], + _set_follow_velocity, + follow_damping_value[i], + delta + ) + else: + for i in 3: + _camera_target.global_position[i] = _smooth_damp( + _follow_target_position[i], + _camera_target.global_position[i], + i, + _follow_velocity_ref[i], + _set_follow_velocity, + follow_damping_value[i], + delta + ) + _transform_output.origin = global_position + _transform_output.basis = global_basis + else: + _camera_target.global_position = _follow_target_position + _transform_output.origin = global_position + + + +func _look_at_target_quat(target_position: Vector3, up_direction: Vector3 = Vector3.UP) -> Quaternion: + var direction: Vector3 = -(target_position - global_position + look_at_offset).normalized() + + var basis_z: Vector3 = direction.normalized() + var basis_x: Vector3 = up_direction.cross(basis_z) + var basis_y: Vector3 = basis_z.cross(basis_x.normalized()) + + var target_basis: Basis = Basis(basis_x, basis_y, basis_z) + + if target_basis.determinant() == 0: + if target_basis.z == Vector3.UP: + global_rotation_degrees.x = -90 + else: + global_rotation_degrees.x = 90 + + _transform_output.basis = global_basis + return quaternion + + return target_basis.get_rotation_quaternion().normalized() + +func _interpolate_rotation(delta: float) -> void: + if _has_up_target: + _up = up_target.get_global_transform().basis.y + + var target_quat: Quaternion = _look_at_target_quat(_look_at_target_position, _up) + + if look_at_damping: + var current_quat: Quaternion = quaternion.normalized() + var damping_time: float = max(0.0001, look_at_damping_value) + var t: float = min(1.0, delta / damping_time) + + var dot: float = current_quat.dot(target_quat) + + if dot < 0.0: + target_quat = -target_quat + dot = -dot + + dot = clampf(dot, -1.0, 1.0) + + var theta: float = acos(dot) * t + var sin_theta: float = sin(theta) + var sin_theta_total: float = sin(acos(dot)) + + # Stop interpolating once sin_theta_total reaches a very low value or 0 + if sin_theta_total < 0.00001: + return + + var ratio_a: float = cos(theta) - dot * sin_theta / sin_theta_total + var ratio_b: float = sin_theta / sin_theta_total + var output: Quaternion = current_quat * ratio_a + target_quat * ratio_b + + _transform_output.basis = Basis(output) + quaternion = output + else: + _transform_output.basis = Basis(target_quat) + quaternion = target_quat + + +func _smooth_damp(target_axis: float, self_axis: float, index: int, current_velocity: float, set_velocity: Callable, damping_time: float, delta: float) -> float: + damping_time = maxf(0.0001, damping_time) + var omega: float = 2 / damping_time + var x: float = omega * delta + var exponential: float = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x) + var diff: float = self_axis - target_axis + var _target_axis: float = target_axis + + var max_change: float = INF * damping_time + diff = clampf(diff, -max_change, max_change) + target_axis = self_axis - diff + + var temp: float = (current_velocity + omega * diff) * delta + set_velocity.call(index, (current_velocity - omega * temp) * exponential) + var output: float = target_axis + (diff + temp) * exponential + + ## To prevent overshooting + if (_target_axis - self_axis > 0.0) == (output > _target_axis): + output = _target_axis + set_velocity.call(index, (output - _target_axis) / delta) + + return output + + +func _get_raw_unprojected_position() -> Vector2: + return get_viewport().get_camera_3d().unproject_position(follow_target.global_position + follow_offset) + + +func _on_dead_zone_changed() -> void: + global_position = _get_target_position_offset_distance() + + +func _get_framed_side_offset() -> Vector2: + var frame_out_bounds: Vector2 + + if viewport_position.x < 0.5 - dead_zone_width / 2: + # Is outside left edge + frame_out_bounds.x = -1 + + if viewport_position.y < 0.5 - dead_zone_height / 2: + # Is outside top edge + frame_out_bounds.y = 1 + + if viewport_position.x > 0.5 + dead_zone_width / 2: + # Is outside right edge + frame_out_bounds.x = 1 + + if viewport_position.y > 0.5001 + dead_zone_height / 2: # 0.501 to resolve an issue where the bottom vertical Dead Zone never becoming 0 when the Dead Zone Vertical parameter is set to 0 + # Is outside bottom edge + frame_out_bounds.y = -1 + + return frame_out_bounds + + +func _set_layer(current_layers: int, layer_number: int, value: bool) -> int: + var mask: int = current_layers + + # From https://github.com/godotengine/godot/blob/51991e20143a39e9ef0107163eaf283ca0a761ea/scene/3d/camera_3d.cpp#L638 + if layer_number < 1 or layer_number > 20: + printerr("Render layer must be between 1 and 20.") + else: + if value: + mask |= 1 << (layer_number - 1) + else: + mask &= ~(1 << (layer_number - 1)) + + return mask + + +func _check_visibility() -> void: + _phantom_camera_manager.pcam_visibility_changed.emit(self) + + +func _follow_target_tree_exiting(target: Node) -> void: + if target == follow_target: + _should_follow = false + if _follow_targets.has(target): + _follow_targets.erase(target) + + +func _should_follow_checker() -> void: + if follow_mode == FollowMode.NONE: + _should_follow = false + return + + if not follow_mode == FollowMode.GROUP: + if is_instance_valid(follow_target): + _should_follow = true + else: + _should_follow = false + + +func _follow_targets_size_check() -> void: + var targets_size: int = 0 + _follow_target_physics_based = false + _follow_targets = [] + for i in follow_targets.size(): + if follow_targets[i] == null: continue + if follow_targets[i].is_inside_tree(): + _follow_targets.append(follow_targets[i]) + targets_size += 1 + _follow_targets_single_target_index = i + _check_physics_body(follow_targets[i]) + if not follow_targets[i].tree_exiting.is_connected(_follow_target_tree_exiting): + follow_targets[i].tree_exiting.connect(_follow_target_tree_exiting.bind(follow_targets[i])) + + match targets_size: + 0: + _should_follow = false + _has_multiple_follow_targets = false + 1: + _should_follow = true + _has_multiple_follow_targets = false + _: + _should_follow = true + _has_multiple_follow_targets = true + + +func _look_at_target_tree_exiting(target: Node) -> void: + if target == look_at_target: + _should_look_at = false + if look_at_targets.has(target): + erase_look_at_targets(target) + +func _up_target_tree_exiting() -> void: + up_target = null + + +func _should_look_at_checker() -> void: + if look_at_mode == LookAtMode.NONE: + _should_look_at = false + return + + if not look_at_mode == LookAtMode.GROUP: + if is_instance_valid(look_at_target): + _should_look_at = true + else: + _should_look_at = false + + +func _look_at_targets_size_check() -> void: + var targets_size: int = 0 + _look_at_target_physics_based = false + + for i in look_at_targets.size(): + if is_instance_valid(look_at_targets[i]): + targets_size += 1 + _look_at_targets_single_target_index = i + _check_physics_body(look_at_targets[i]) + if not look_at_targets[i].tree_exiting.is_connected(_look_at_target_tree_exiting): + look_at_targets[i].tree_exiting.connect(_look_at_target_tree_exiting.bind(look_at_targets[i])) + + match targets_size: + 0: + _should_look_at = false + _has_multiple_look_at_targets = false + 1: + _should_look_at = true + _has_multiple_look_at_targets = false + _: + _should_look_at = true + _has_multiple_look_at_targets = true + + +func _noise_emitted(emitter_noise_output: Transform3D, emitter_layer: int) -> void: + if noise_emitter_layer & emitter_layer != 0: + noise_emitted.emit(emitter_noise_output) + + +func _check_physics_body(target: Node3D) -> void: + if target is PhysicsBody3D: + var show_jitter_tips := ProjectSettings.get_setting("phantom_camera/tips/show_jitter_tips") + var physics_interpolation_enabled := ProjectSettings.get_setting("physics/common/physics_interpolation") + + ## NOTE - Feature Toggle + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor < 4: + if show_jitter_tips == null: # Default value is null when referencing custom Project Setting + print_rich("Following or Looking at a [b]PhysicsBody3D[/b] node will likely result in jitter - on lower physics ticks in particular.") + print_rich("If possible, will recommend upgrading to Godot 4.4, as it has built-in support for 3D Physics Interpolation, which will mitigate this issue.") + print_rich("Until then, try following the guide on the [url=https://phantom-camera.dev/support/faq#i-m-seeing-jitter-what-can-i-do]documentation site[/url] for better results.") + print_rich("This tip can be disabled from within [code]Project Settings / Phantom Camera / Tips / Show Jitter Tips[/code]") + return + ## NOTE - Only supported in Godot 4.4 or above + elif not physics_interpolation_enabled and show_jitter_tips == null: # Default value is null when referencing custom Project Setting + printerr("Physics Interpolation is disabled in the Project Settings, recommend enabling it to smooth out physics-based camera movement") + print_rich("This tip can be disabled from within [code]Project Settings / Phantom Camera / Tips / Show Jitter Tips[/code]") + _follow_target_physics_based = true + else: + _is_parents_physics(target) + physics_target_changed.emit() + + +func _is_parents_physics(target: Node = self) -> void: + var current_node: Node = target + while current_node: + current_node = current_node.get_parent() + if not current_node is PhysicsBody3D: continue + _follow_target_physics_based = true + + +func _camera_resource_changed() -> void: + camera_3d_resource_changed.emit() + +#endregion + +#region Public Functions + +# TBD +#func get_unprojected_position() -> Vector2: + #var unprojected_position: Vector2 = _get_raw_unprojected_position() + #var viewport_width: float = get_viewport().size.x + #var viewport_height: float = get_viewport().size.y + #var camera_aspect: Camera3D.KeepAspect = get_viewport().get_camera_3d().keep_aspect + #var visible_rect_size: Vector2 = get_viewport().size +# + #unprojected_position = unprojected_position - visible_rect_size / 2 + #if camera_aspect == Camera3D.KeepAspect.KEEP_HEIGHT: +## print("Landscape View") + #var aspect_ratio_scale: float = viewport_width / viewport_height + #unprojected_position.x = (unprojected_position.x / aspect_ratio_scale + 1) / 2 + #unprojected_position.y = (unprojected_position.y + 1) / 2 + #else: +## print("Portrait View") + #var aspect_ratio_scale: float = viewport_height / viewport_width + #unprojected_position.x = (unprojected_position.x + 1) / 2 + #unprojected_position.y = (unprojected_position.y / aspect_ratio_scale + 1) / 2 +# + #return unprojected_position + + +## Returns the [Transform3D] value based on the [member follow_mode] / [member look_at_mode] target value. +func get_transform_output() -> Transform3D: + return _transform_output + + +## Returns the noise [Transform3D] value. +func get_noise_transform() -> Transform3D: + return _transform_noise + + +## Emits a noise based on a custom [Transform3D] value.[br] +## Use this function if you wish to make use of external noise patterns from, for example, other addons. +func emit_noise(value: Transform3D) -> void: + noise_emitted.emit(value) + + +## Teleports the [param PhantomCamera3D] and [Camera3D] to their designated position, +## bypassing the damping process. +func teleport_position() -> void: + _follow_velocity_ref = Vector3.ZERO + _set_follow_position() + _transform_output.origin = _follow_target_position + _phantom_camera_manager.pcam_teleport.emit(self) + + +# TODO: Enum link does link to anywhere is being tracked in: https://github.com/godotengine/godot/issues/106828 +## Returns [code]true[/code] if this [param PhantomCamera3D]'s [member follow_mode] is not set to [constant FollowMode.NONE] +## and has a valid [member follow_target]. +func is_following() -> bool: + return _should_follow + +# TODO: Enum link does link to anywhere is being tracked in: https://github.com/godotengine/godot/issues/106828 +## Returns [code]true[/code] if this [param PhantomCamera3D]'s [member look_at_mode] is not set to [constant LookAtMode.NONE] +## and has a valid [member look_at_target]. +func is_looking() -> bool: + return _should_look_at + +#endregion + + +#region Setter & Getter Functions + +## Assigns the value of the [param has_tweened] property.[br] +## [b][color=yellow]Important:[/color][/b] This value can only be changed +## from the [PhantomCameraHost] script. +func set_tween_skip(caller: Node, value: bool) -> void: + if is_instance_of(caller, PhantomCameraHost): + _tween_skip = value + else: + printerr("Can only be called PhantomCameraHost class") +## Returns the current [param has_tweened] value. +func get_tween_skip() -> bool: + return _tween_skip + + +## Assigns new [member priority] value. +func set_priority(value: int) -> void: + priority = abs(value) # TODO - Make any minus values be 0 + if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return + Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).pcam_priority_changed.emit(self) +## Gets current [param Priority] value. +func get_priority() -> int: + return priority + + +## Assigns a new [PhantomCameraTween] resource to the [param PhantomCamera3D]. +func set_tween_resource(value: PhantomCameraTween) -> void: + tween_resource = value +## Gets the [param PhantomCameraTween] resource assigned to the [param PhantomCamera3D]. +## Returns null if there's nothing assigned to it. +func get_tween_resource() -> PhantomCameraTween: + return tween_resource + +## Assigns a new [param Tween Duration] to the [member tween_resource] value.[br] +## The duration value is in seconds. +func set_tween_duration(value: float) -> void: + tween_resource.duration = value +## Gets the current [param Tween] Duration value. The duration value is in +## [param seconds]. +func get_tween_duration() -> float: + return tween_resource.duration + +## Assigns a new [param Tween Transition] to the [member tween_resource] value.[br] +## The duration value is in seconds. +func set_tween_transition(value: int) -> void: + tween_resource.transition = value +## Gets the current [param Tween Transition] value. +func get_tween_transition() -> int: + return tween_resource.transition + +## Assigns a new [param Tween Ease] to the [member tween_resource] value.[br] +## The duration value is in seconds. +func set_tween_ease(value: int) -> void: + tween_resource.ease = value +## Gets the current [param Tween Ease] value. +func get_tween_ease() -> int: + return tween_resource.ease + +## Sets the [param PhantomCamera3D] active state[br] +## [b][color=yellow]Important:[/color][/b] This value can only be changed +## from the [PhantomCameraHost] script. +func set_is_active(node: Node, value: bool) -> void: + if node is PhantomCameraHost: + _is_active = value + if value: + _should_follow_checker() + else: + printerr("PCams can only be set from the PhantomCameraHost") +## Gets current active state of the [param PhantomCamera3D]. +## If it returns true, it means the [param PhantomCamera3D] is what the +## [param Camera3D] is currently following. +func is_active() -> bool: + return _is_active + + +## Enables or disables the [member tween_on_load]. +func set_tween_on_load(value: bool) -> void: + tween_on_load = value +## Gets the current [member tween_on_load] value. +func get_tween_on_load() -> bool: + return tween_on_load + + +## Sets the [member host_layers] value. +func set_host_layers(value: int) -> void: + host_layers = value + if is_instance_valid(_phantom_camera_manager): + _phantom_camera_manager.pcam_host_layer_changed.emit(self) + +## Enables or disables a given layer of [member host_layers]. +func set_host_layers_value(layer: int, value: bool) -> void: + host_layers = _set_layer(host_layers, layer, value) + +## Gets the current [member host_layers]. +func get_host_layers() -> int: + return host_layers + + +## Gets the current follow mode as an enum int based on [member FollowMode] enum.[br] +## [b]Note:[/b] Setting [member follow_mode] has purposely not been added. +## A separate [param PhantomCamera3D] instance should be used instead. +func get_follow_mode() -> int: + return follow_mode + + +## Assigns a new [Node3D] as the [member follow_target]. +func set_follow_target(value: Node3D) -> void: + if follow_mode == FollowMode.NONE or follow_mode == FollowMode.GROUP: return + if follow_target == value: return + follow_target = value + _follow_target_physics_based = false + if is_instance_valid(value): + if follow_mode == FollowMode.PATH: + if is_instance_valid(follow_path): + _should_follow = true + else: + _should_follow = false + else: + _should_follow = true + _check_physics_body(value) + if follow_mode == FollowMode.THIRD_PERSON and is_instance_valid(_follow_spring_arm): + _follow_spring_arm.add_excluded_object(follow_target) + if not follow_target.tree_exiting.is_connected(_follow_target_tree_exiting): + follow_target.tree_exiting.connect(_follow_target_tree_exiting.bind(follow_target)) + else: + if not follow_mode == FollowMode.GROUP: + _should_follow = false + follow_target_changed.emit() + notify_property_list_changed() +## Removes the current [Node3D] [member follow_target]. +func erase_follow_target() -> void: + follow_target = null +## Gets the current Node3D target. +func get_follow_target() -> Node3D: + return follow_target + + +## Assigns a new [Path3D] to the [member follow_path] property. +func set_follow_path(value: Path3D) -> void: + follow_path = value + if is_instance_valid(follow_path): + _should_follow_checker() + else: + _should_follow = false + +## Erases the current [Path3D] from [member follow_path] property. +func erase_follow_path() -> void: + follow_path = null + +## Gets the current [Path3D] from the [member follow_path] property. +func get_follow_path() -> Path3D: + return follow_path + + +## Assigns a new [param follow_targets] array value. +func set_follow_targets(value: Array[Node3D]) -> void: + if not follow_mode == FollowMode.GROUP: return + if follow_targets == value: return + follow_targets = value + _follow_targets_size_check() + + +## Adds a single [Node3D] to [member follow_targets] array. +func append_follow_targets(value: Node3D) -> void: + if not is_instance_valid(value): + printerr(value, " is not a valid Node3D instance") + return + + if not follow_targets.has(value): + follow_targets.append(value) + _follow_targets_size_check() + else: + printerr(value, " is already part of Follow Group") + +## Adds an Array of type [Node3D] to [member follow_targets] array. +func append_follow_targets_array(value: Array[Node3D]) -> void: + for target in value: + if not is_instance_valid(target): continue + if not follow_targets.has(target): + follow_targets.append(target) + _follow_targets_size_check() + else: + printerr(value, " is already part of Follow Group") + +## Removes [Node3D] from [member follow_targets]. +func erase_follow_targets(value: Node3D) -> void: + follow_targets.erase(value) + _follow_targets_size_check() + + +## Gets all [Node3D] from [follow_targets]. +func get_follow_targets() -> Array[Node3D]: + return follow_targets + + +## Assigns a new [param Vector3] for the [param follow_offset] property. +func set_follow_offset(value: Vector3) -> void: + var temp_offset: Vector3 = follow_offset + follow_offset = value + + if follow_axis_lock != FollowLockAxis.NONE: + temp_offset = temp_offset - value + match value: + FollowLockAxis.X: + _follow_axis_lock_value.x = _transform_output.origin.x + temp_offset.x + FollowLockAxis.Y: + _follow_axis_lock_value.y = _transform_output.origin.y + temp_offset.y + FollowLockAxis.Z: + _follow_axis_lock_value.z = _transform_output.origin.z + temp_offset.z + FollowLockAxis.XY: + _follow_axis_lock_value.x = _transform_output.origin.x + temp_offset.x + _follow_axis_lock_value.y = _transform_output.origin.y + temp_offset.y + FollowLockAxis.XZ: + _follow_axis_lock_value.x = _transform_output.origin.x + temp_offset.x + _follow_axis_lock_value.z = _transform_output.origin.z + temp_offset.z + FollowLockAxis.YZ: + _follow_axis_lock_value.y = _transform_output.origin.y + temp_offset.y + _follow_axis_lock_value.z = _transform_output.origin.z + temp_offset.z + FollowLockAxis.XYZ: + _follow_axis_lock_value.x = _transform_output.origin.x + temp_offset.x + _follow_axis_lock_value.y = _transform_output.origin.y + temp_offset.y + _follow_axis_lock_value.z = _transform_output.origin.z + temp_offset.z + +## Gets the current [param Vector3] for the [param follow_offset] property. +func get_follow_offset() -> Vector3: + return follow_offset + + +## Enables or disables [member follow_damping]. +func set_follow_damping(value: bool) -> void: + follow_damping = value + notify_property_list_changed() + +## Gets the currents [member follow_damping] property. +func get_follow_damping() -> bool: + return follow_damping + + +## Assigns new [member follow_damping_value] value. +func set_follow_damping_value(value: Vector3) -> void: + ## TODO - Should be using @export_range once minimum version support is Godot 4.3 + if value.x < 0: value.x = 0 + elif value.y < 0: value.y = 0 + elif value.z < 0: value.z = 0 + follow_damping_value = value + +## Gets the currents [member follow_damping_value] value. +func get_follow_damping_value() -> Vector3: + return follow_damping_value + + +## Assigns a new [member follow_distance] value. +func set_follow_distance(value: float) -> void: + follow_distance = value + +## Gets [member follow_distance] value. +func get_follow_distance() -> float: + return follow_distance + + +## Enables or disables [member auto_follow_distance] when using Group Follow. +func set_auto_follow_distance(value: bool) -> void: + auto_follow_distance = value + notify_property_list_changed() + +## Gets [member auto_follow_distance] state. +func get_auto_follow_distance() -> bool: + return auto_follow_distance + + +## Assigns new [member auto_follow_distance_min] value. +func set_auto_follow_distance_min(value: float) -> void: + auto_follow_distance_min = value + +## Gets [member auto_follow_distance_min] value. +func get_auto_follow_distance_min() -> float: + return auto_follow_distance_min + + +## Assigns new [member auto_follow_distance_max] value. +func set_auto_follow_distance_max(value: float) -> void: + auto_follow_distance_max = value +## Gets [member auto_follow_distance_max] value. +func get_auto_follow_distance_max() -> float: + return auto_follow_distance_max + + +## Assigns new [member auto_follow_distance_divisor] value. +func set_auto_follow_distance_divisor(value: float) -> void: + auto_follow_distance_divisor = value + +## Gets [member auto_follow_distance_divisor] value. +func get_auto_follow_distance_divisor() -> float: + return auto_follow_distance_divisor + + +## Assigns new rotation (in radians) value to [SpringArm3D] for +## [param ThirdPerson] [enum FollowMode]. +func set_third_person_rotation(value: Vector3) -> void: + if not _is_third_person_follow: + printerr("Follow Mode is not set to Third Person") + return + _follow_spring_arm.rotation = value + +## Gets the rotation value (in radians) from the [SpringArm3D] for +## [param ThirdPerson] [enum FollowMode]. +func get_third_person_rotation() -> Vector3: + if not _is_third_person_follow: + printerr("Follow Mode is not set to Third Person") + return Vector3.ZERO + return _follow_spring_arm.rotation + + +## Assigns new rotation (in degrees) value to [SpringArm3D] for +## [param ThirdPerson] [enum FollowMode]. +func set_third_person_rotation_degrees(value: Vector3) -> void: + if not _is_third_person_follow: + printerr("Follow Mode is not set to Third Person") + return + _follow_spring_arm.rotation_degrees = value + +## Gets the rotation value (in degrees) from the [SpringArm3D] for +## [param ThirdPerson] [enum FollowMode]. +func get_third_person_rotation_degrees() -> Vector3: + if not _is_third_person_follow: + printerr("Follow Mode is not set to Third Person") + return Vector3.ZERO + return _follow_spring_arm.rotation_degrees + + +## Assigns new [Quaternion] value to [SpringArm3D] for [param ThirdPerson] +## [enum FollowMode]. +func set_third_person_quaternion(value: Quaternion) -> void: + if not _is_third_person_follow: + printerr("Follow Mode is not set to Third Person") + return + _follow_spring_arm.quaternion = value + +## Gets the [Quaternion] value of the [SpringArm3D] for [param ThirdPerson] +## [enum Follow mode]. +func get_third_person_quaternion() -> Quaternion: + if not _is_third_person_follow: + printerr("Follow Mode is not set to Third Person") + return Quaternion.IDENTITY + return _follow_spring_arm.quaternion + + +## Assigns a new ThirdPerson [member SpringArm3D.length] value. +func set_spring_length(value: float) -> void: + follow_distance = value + if not is_instance_valid(_follow_spring_arm): return + _follow_spring_arm.spring_length = value + +## Gets the [member SpringArm3D.length] +## from a [param ThirdPerson] [enum follow_mode] instance. +func get_spring_length() -> float: + return follow_distance + + +## Assigns a new [member collision_mask] to the [SpringArm3D] when [enum FollowMode] +## is set to [param ThirdPerson]. +func set_collision_mask(value: int) -> void: + collision_mask = value + if not is_instance_valid(_follow_spring_arm): return + _follow_spring_arm.collision_mask = collision_mask + +## Enables or disables a specific [member collision_mask] layer for the +## [SpringArm3D] when [enum FollowMode] is set to [param ThirdPerson]. +func set_collision_mask_value(value: int, enabled: bool) -> void: + collision_mask = _set_layer(collision_mask, value, enabled) + if not is_instance_valid(_follow_spring_arm): return + _follow_spring_arm.collision_mask = collision_mask + +## Gets [member collision_mask] from the [SpringArm3D] when [enum FollowMode] +## is set to [param ThirdPerson]. +func get_collision_mask() -> int: + return collision_mask + + +## Assigns a new [SpringArm3D.shape] when [enum FollowMode] +## is set to [param ThirdPerson]. +func set_shape(value: Shape3D) -> void: + shape = value + if not is_instance_valid(_follow_spring_arm): return + _follow_spring_arm.shape = shape + +## Gets [param ThirdPerson] [member SpringArm3D.shape] value. +func get_shape() -> Shape3D: + return shape + + +## Assigns a new [member SpringArm3D.margin] value when [enum FollowMode] +## is set to [param ThirdPerson]. +func set_margin(value: float) -> void: + margin = value + if not is_instance_valid(_follow_spring_arm): return + _follow_spring_arm.margin = margin + +## Gets the [SpringArm3D.margin] when [enum FollowMode] is set to +## [param ThirdPerson]. +func get_margin() -> float: + return margin + + +## Gets the current [member look_at_mode]. Value is based on [enum LookAtMode] +## enum.[br] +## Note: To set a new [member look_at_mode], a separate [param PhantomCamera3D] should be used. +func get_look_at_mode() -> int: + return look_at_mode + + +## Assigns new [Node3D] as [member look_at_target]. +func set_look_at_target(value: Node3D) -> void: + if look_at_mode == LookAtMode.NONE: return + if look_at_target == value: return + look_at_target = value + if not look_at_mode == LookAtMode.GROUP: + if is_instance_valid(look_at_target): + _should_look_at = true + _check_physics_body(value) + if not look_at_target.tree_exiting.is_connected(_look_at_target_tree_exiting): + look_at_target.tree_exiting.connect(_look_at_target_tree_exiting.bind(look_at_target)) + else: + _should_look_at = false + elif look_at_targets.size() == 0: + _should_look_at = false + + look_at_target_changed.emit() + notify_property_list_changed() + +## Gets current [Node3D] from [member look_at_target] property. +func get_look_at_target() -> Node3D: + return look_at_target + + +## Sets an array of type [Node3D] to [member set_look_at_targets]. +func set_look_at_targets(value: Array[Node3D]) -> void: + if not look_at_mode == LookAtMode.GROUP: return + if look_at_targets == value: return + look_at_targets = value + + _look_at_targets_size_check() + notify_property_list_changed() + +## Appends a [Node3D] to [member look_at_targets] array. +func append_look_at_target(value: Node3D) -> void: + if not is_instance_valid(value): + printerr(value, "is an invalid Node3D instance") + return + + if not look_at_targets.has(value): + look_at_targets.append(value) + _look_at_targets_size_check() + else: + printerr(value, " is already part of Look At Group") + + +## Appends an array of type [Node3D] to [member look_at_targets] array. +func append_look_at_targets_array(value: Array[Node3D]) -> void: + for val in value: + if not is_instance_valid(val): continue + if not look_at_targets.has(val): + look_at_targets.append(val) + _look_at_targets_size_check() + else: + printerr(val, " is already part of Look At Group") + +## Removes [Node3D] from [member look_at_targets] array. +func erase_look_at_targets(value: Node3D) -> void: + if look_at_targets.has(value): + look_at_targets.erase(value) + _look_at_targets_size_check() + else: + printerr(value, " is not part of Look At Group") + + +## Removes [Node3D] from [member look_at_targets] array. [br] +## @deprecated: Use [member erase_look_at_targets] instead. +func erase_look_at_targets_member(value: Node3D) -> void: + printerr("erase_look_at_targets_member is deprecated, use erase_look_at_targets instead") + erase_look_at_targets(value) + +## Gets all the [Node3D] instances in [member look_at_targets]. +func get_look_at_targets() -> Array[Node3D]: + return look_at_targets + + +## Assigns a new [Vector3] to the [member look_at_offset] value. +func set_look_at_offset(value: Vector3) -> void: + look_at_offset = value + +## Gets the current [member look_at_offset] value. +func get_look_at_offset() -> Vector3: + return look_at_offset + + +## Enables or disables [member look_at_damping]. +func set_look_at_damping(value: bool) -> void: + look_at_damping = value + notify_property_list_changed() + +## Gets the currents [member look_at_damping] property. +func get_look_at_damping() -> bool: + return look_at_damping + + +## Assigns new [member look_at_damping_value] value. +func set_look_at_damping_value(value: float) -> void: + look_at_damping_value = value + +## Gets the currents [member look_at_damping_value] value. +func get_look_at_damping_value() -> float: + return look_at_damping_value + +## Assigns the Follow Axis. +func set_follow_axis_lock(value: FollowLockAxis) -> void: + follow_axis_lock = value + + # Wait for the node to be ready before setting lock + if not is_node_ready(): await ready + + # Prevent axis lock from working in the editor + if value != FollowLockAxis.NONE and not Engine.is_editor_hint(): + _follow_axis_is_locked = true + match value: + FollowLockAxis.X: + _follow_axis_lock_value.x = _transform_output.origin.x + FollowLockAxis.Y: + _follow_axis_lock_value.y = _transform_output.origin.y + FollowLockAxis.Z: + _follow_axis_lock_value.z = _transform_output.origin.z + FollowLockAxis.XY: + _follow_axis_lock_value.x = _transform_output.origin.x + _follow_axis_lock_value.y = _transform_output.origin.y + FollowLockAxis.XZ: + _follow_axis_lock_value.x = _transform_output.origin.x + _follow_axis_lock_value.z = _transform_output.origin.z + FollowLockAxis.YZ: + _follow_axis_lock_value.y = _transform_output.origin.y + _follow_axis_lock_value.z = _transform_output.origin.z + FollowLockAxis.XYZ: + _follow_axis_lock_value.x = _transform_output.origin.x + _follow_axis_lock_value.y = _transform_output.origin.y + _follow_axis_lock_value.z = _transform_output.origin.z + else: + _follow_axis_is_locked = false + +## Gets the current [member follow_axis_lock] property. Value is based on [enum FollowLockAxis] enum. +func get_follow_axis_lock() -> FollowLockAxis: + return follow_axis_lock + + +## Sets the [member up] value. +func set_up(value: Vector3) -> void: + if value == Vector3.ZERO: + value = Vector3.UP + push_warning("Up value cannot be (0, 0, 0), resetting to (0, 1, 0).") + + up = value + if not _has_up_target: + _up = value + +## Gets the [member up] value. +func get_up() -> Vector3: + return up + + +## Sets the [member up_target]. +func set_up_target(value: Node3D) -> void: + up_target = value + if is_instance_valid(value): + _has_up_target = true + if not value.tree_exiting.is_connected(_up_target_tree_exiting): + value.tree_exiting.connect(_up_target_tree_exiting) + else: + _has_up_target = false + _up = up + notify_property_list_changed() + +## Gets the [member up_target]. +func get_up_target() -> Node3D: + return up_target + + +## Sets a [PhantomCameraNoise3D] resource. +func set_noise(value: PhantomCameraNoise3D) -> void: + noise = value + if value != null: + _has_noise_resource = true + noise.set_trauma(1) + else: + _has_noise_resource = false + _transform_noise = Transform3D() + +func get_noise() -> PhantomCameraNoise3D: + return noise + +func has_noise_resource() -> bool: + return _has_noise_resource + + +## Sets the [member noise_emitter_layer] value. +func set_noise_emitter_layer(value: int) -> void: + noise_emitter_layer = value + +## Enables or disables a given layer of [member noise_emitter_layer]. +func set_noise_emitter_layer_value(value: int, enabled: bool) -> void: + noise_emitter_layer = _set_layer(noise_emitter_layer, value, enabled) + +## Returns the [member noise_emitter_layer]. +func get_noise_emitter_layer() -> int: + return noise_emitter_layer + + +## Sets [member inactive_update_mode] property. +func set_inactive_update_mode(value: int) -> void: + inactive_update_mode = value + +## Gets [member inactive_update_mode] property. +func get_inactive_update_mode() -> int: + return inactive_update_mode + + +## Assigns a [Camera3DResource]. +func set_camera_3d_resource(value: Camera3DResource) -> void: + camera_3d_resource = value + camera_3d_resource_changed.emit() + if value: + if not camera_3d_resource.changed.is_connected(_camera_resource_changed): + camera_3d_resource.changed.connect(_camera_resource_changed) + +## Gets the [Camera3DResource]. +func get_camera_3d_resource() -> Camera3DResource: + return camera_3d_resource + + +func set_keep_aspect(value: int) -> void: + if not camera_3d_resource: + printerr("Can't assign a keep_aspect value. No Camera3DResource assigned to ", name) + return + keep_aspect = value + camera_3d_resource_property_changed.emit("keep_aspect", value) + +func get_keep_aspect() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.keep_aspect + + +## Assigns a new [member Camera3D.cull_mask] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_cull_mask(value: int) -> void: + if not camera_3d_resource: + printerr("Can't assign a cull_mask value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.cull_mask = value + camera_3d_resource_property_changed.emit("cull_mask", value) + +## Enables or disables a specific [member Camera3D.cull_mask] layer.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_cull_mask_value(layer_number: int, value: bool) -> void: + if not camera_3d_resource: + printerr("Can't assign a cull_mask value. No Camera3DResource assigned to ", name) + return + var mask: int = _set_layer(get_cull_mask(), layer_number, value) + camera_3d_resource.cull_mask = mask + camera_3d_resource_property_changed.emit("cull_mask", mask) + +## Gets the [member Camera3D.cull_mask] value assigned to the [Camera3DResource]. +func get_cull_mask() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.cull_mask + + +## Assigns a new [Environment] resource to the [Camera3DResource]. +func set_environment(value: Environment) -> void: + environment = value + camera_3d_resource_property_changed.emit("environment", value) + +## Gets the [Camera3D.environment] value assigned to the [Camera3DResource]. +func get_environment() -> Environment: + return environment + + +## Assigns a new [CameraAttributes] resource to the [Camera3DResource]. +func set_attributes(value: CameraAttributes) -> void: + attributes = value + camera_3d_resource_property_changed.emit("attributes", value) + +## Gets the [Camera3D.attributes] value assigned to the [Camera3DResource]. +func get_attributes() -> CameraAttributes: + return attributes + + +## Assigns a new [member Camera3D.h_offset] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_h_offset(value: float) -> void: + if not camera_3d_resource: + printerr("Can't assign a h_offset value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.h_offset = value + camera_3d_resource_property_changed.emit("h_offset", value) + +## Gets the [member Camera3D.h_offset] value assigned to the [param Camera3DResource]. +func get_h_offset() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.h_offset + + +## Assigns a new [Camera3D.v_offset] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_v_offset(value: float) -> void: + if not camera_3d_resource: + printerr("Can't assign a v_offset value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.v_offset = value + camera_3d_resource_property_changed.emit("v_offset", value) + +## Gets the [member Camera3D.v_offset] value assigned to the [param Camera3DResource]. +func get_v_offset() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.v_offset + + +## Assigns a new [Camera3D.projection] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_projection(value: int) -> void: + if not camera_3d_resource: + printerr("Can't assign a projection value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.projection = value + camera_3d_resource_property_changed.emit("projection", value) + +## Gets the [member Camera3D.projection] value assigned to the [param Camera3DResource]. +func get_projection() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.projection + + +## Assigns a new [member Camera3D.fov] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_fov(value: float) -> void: + if not camera_3d_resource: + printerr("Can't assign a fov value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.fov = value + camera_3d_resource_property_changed.emit("fov", value) + +## Gets the [member Camera3D.fov] value assigned to the [param Camera3DResource]. +func get_fov() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.fov + + +## Assigns a new [member Camera3D.size] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_size(value: float) -> void: + if not camera_3d_resource: + printerr("Can't assign a size value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.size = value + camera_3d_resource_property_changed.emit("size", value) + +## Gets the [member Camera3D.size] value assigned to the [param Camera3DResource]. +func get_size() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.size + + +## Assigns a new [member Camera3D.frustum_offset] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_frustum_offset(value: Vector2) -> void: + if not camera_3d_resource: + printerr("Can't assign a frustum_offset value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.frustum_offset = value + camera_3d_resource_property_changed.emit("frustum_offset", value) + +## Gets the [member Camera3D.frustum_offset] value assigned to the [param Camera3DResource]. +func get_frustum_offset() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.frustum_offset + + +## Assigns a new [member Camera3D.near] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_near(value: float) -> void: + if not camera_3d_resource: + printerr("Can't assign a near value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.near = value + camera_3d_resource_property_changed.emit("near", value) + +## Gets the [member Camera3D.near] value assigned to the [param Camera3DResource]. +func get_near() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.near + + +## Assigns a new [member Camera3D.far] value.[br] +## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to +## this [param PhantomCamera3D]. +func set_far(value: float) -> void: + if not camera_3d_resource: + printerr("Can't assign a far value. No Camera3DResource assigned to ", name) + return + camera_3d_resource.far = value + camera_3d_resource_property_changed.emit("far", value) + +## Gets the [member Camera3D.far] value assigned to the [param Camera3DResource]. +func get_far() -> Variant: + if not camera_3d_resource: return null + return camera_3d_resource.far + + +func get_follow_target_physics_based() -> bool: + return _follow_target_physics_based + + +func get_class() -> String: + return "PhantomCamera3D" + + +func is_class(value) -> bool: + return value == "PhantomCamera3D" + +#endregion diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd new file mode 100644 index 0000000..43f6cf4 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd @@ -0,0 +1,29 @@ +@tool +extends RefCounted + +#region Constants + +#const PhantomCameraHost: Script = preload("res://addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd") + +const CAMERA_2D_NODE_NAME: StringName = "Camera2D" +const CAMERA_3D_NODE_NAME: StringName = "Camera3D" +const PCAM_HOST_NODE_NAME: StringName = "PhantomCameraHost" +const PCAM_MANAGER_NODE_NAME: String = "PhantomCameraManager" # TODO - Convert to StringName once https://github.com/godotengine/godot/pull/72702 is merged +const PCAM_2D_NODE_NAME: StringName = "PhantomCamera2D" +const PCAM_3D_NODE_NAME: StringName = "PhantomCamera3D" +const PCAM_HOST: StringName = "phantom_camera_host" + +const COLOR_2D: Color = Color("8DA5F3") +const COLOR_3D: Color = Color("FC7F7F") +const COLOR_PCAM: Color = Color("3AB99A") +const COLOR_PCAM_33: Color = Color("3ab99a33") +const PCAM_HOST_COLOR: Color = Color("E0E0E0") + +#endregion + +#region Group Names + +const PCAM_GROUP_NAME: StringName = "phantom_camera_group" +const PCAM_HOST_GROUP_NAME: StringName = "phantom_camera_host_group" + +#endregion diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_2d.gd b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_2d.gd new file mode 100644 index 0000000..7306810 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_2d.gd @@ -0,0 +1,264 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_noise_emitter_2d.svg") +class_name PhantomCameraNoiseEmitter2D +extends Node2D + +## Emits positional and rotational noise to active [PhantomCamera2D]s and its corresponding [Camera2D]. +## +## Is a node meant to apply positional and rotational noise, also referred to as shake, to the [Camera2D]. +## It is designed for use cases such as when hitting or when being hit, earthquakes or to add a +## bit of slight movement to the camera to make it feel less static. +## The emitter can affect multiple [PhantomCamera2D] in a given scene based on which [member noise_emitter_layer] +## are enabled by calling its [method emit] function. At least one corresponding layer has to be +## set on the [PhantomCamera2D] and the emitter node. + +const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +#region Exported Proerpties + +## The [PhantomCameraNoise2D] resource that defines the noise pattern. +@export var noise: PhantomCameraNoise2D = null: + set = set_noise, + get = get_noise + +## If true, previews the noise in the editor - can be seen in the viewfinder. +@export var preview: bool = false: + set(value): + preview = value + _play = value + get: + return preview + +## If true, repeats the noise indefinitely once started. Otherwise, it will only be triggered once. [br] +@export var continuous: bool = false: + set = set_continuous, + get = get_continuous + +## Determines how long the noise should take to reach full [member intensity] once started.[br] +## The value is set in [b]seconds[/b]. +@export_exp_easing("positive_only", "suffix: s") var growth_time: float = 0: + set = set_growth_time, + get = get_growth_time + +## Sets the duration for the camera noise if [member continuous] is set to [b]false[/b].[br][br] +## The value is set in [b]seconds[/b]. +@export_range(0, 10, 0.001, "or_greater", "suffix: s") var duration: float = 1.0: + set = set_duration, + get = get_duration + +## Determines how long the noise should take to come to a full stop.[br] +## The value is set in [b]seconds[/b]. +@export_exp_easing("attenuation", "positive_only", "suffix: s") var decay_time: float = 0: + set = set_decay_time, + get = get_decay_time + +## Enabled layers will affect [PhantomCamera2D] nodes with at least one corresponding layer enabled.[br] +## Enabling multiple corresponding layers on the same [PhantomCamera2D] causes no additional effect. +@export_flags_2d_render var noise_emitter_layer: int = 1: + set = set_noise_emitter_layer, + get = get_noise_emitter_layer + +#endregion + + +#region Private Variables + +var _play: bool = false: + set(value): + _play = value + if value: + _elasped_play_time = 0 + _decay_countdown = 0 + _play = true + _should_grow = true + _start_duration_countdown = false + _should_decay = false + else: + _should_decay = true + if noise.randomize_noise_seed: + noise.noise_seed = randi() & 1000 + else: + noise.reset_noise_time() + get: + return _play + +var _start_duration_countdown: bool = false + +var _decay_countdown: float = 0 + +var _should_grow: bool = false + +var _should_decay: bool = false + +var _elasped_play_time: float = 0 + +var _noise_output: Transform2D = Transform2D() + +# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box. +var _phantom_camera_manager: Node + +#endregion + +#region Private Functions + +func _get_configuration_warnings() -> PackedStringArray: + if noise == null: + return ["Noise resource is required in order to trigger emitter."] + else: + return [] + + +func _validate_property(property) -> void: + if property.name == "duration" and continuous: + property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _enter_tree() -> void: + _phantom_camera_manager = get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME) + + +func _process(delta: float) -> void: + if not _play and not _should_decay: return + if noise == null: + printerr("Noise resource missing in ", name) + _play = false + return + + _elasped_play_time += delta + + if _should_grow: + noise.set_trauma(minf(_elasped_play_time / growth_time, 1)) + if _elasped_play_time >= growth_time: + _should_grow = false + _start_duration_countdown = true + noise.set_trauma(1) + else: + noise.set_trauma(1) + + if not continuous: + if _start_duration_countdown: + if _elasped_play_time >= duration + growth_time: + _should_decay = true + _start_duration_countdown = false + + if _should_decay: + _decay_countdown += delta + noise.set_trauma(maxf(1 - (_decay_countdown / decay_time), 0)) + if _decay_countdown >= decay_time: + noise.set_trauma(0) + _play = false + preview = false + _should_decay = false + _elasped_play_time = 0 + _decay_countdown = 0 + + _noise_output = noise.get_noise_transform(delta) + _phantom_camera_manager.noise_2d_emitted.emit(_noise_output, noise_emitter_layer) + + +func _set_layer(current_layers: int, layer_number: int, value: bool) -> int: + var mask: int = current_layers + + # From https://github.com/godotengine/godot/blob/51991e20143a39e9ef0107163eaf283ca0a761ea/scene/3d/camera_3d.cpp#L638 + if layer_number < 1 or layer_number > 20: + printerr("Layer must be between 1 and 20.") + else: + if value: + mask |= 1 << (layer_number - 1) + else: + mask &= ~(1 << (layer_number - 1)) + + return mask + +#endregion + + +#region Public Functions + +## Emits noise to the [PhantomCamera2D]s that has at least one matching layers. +func emit() -> void: + if _play: _play = false + _play = true + +## Returns the state for the emitter. If true, the emitter is currently emitting. +func is_emitting() -> bool: + return _play + +## Stops the emitter from emitting noise. +func stop(should_decay: bool = true) -> void: + if should_decay: + _should_decay = true + else: + _play = false + +## Toggles the emitter on and off. +func toggle() -> void: + _play = !_play + +#endregion + + +#region Setter & Getter Functions + +## Sets the [member noise] resource. +func set_noise(value: PhantomCameraNoise2D) -> void: + noise = value + update_configuration_warnings() + +## Returns the [member noise] resource. +func get_noise() -> PhantomCameraNoise2D: + return noise + + +## Sets the [member continous] value. +func set_continuous(value: bool) -> void: + continuous = value + notify_property_list_changed() + +## Gets the [member continous] value. +func get_continuous() -> bool: + return continuous + + +## Sets the [member growth_time] value. +func set_growth_time(value: float) -> void: + growth_time = value + +## Returns the [member growth_time] value. +func get_growth_time() -> float: + return growth_time + + +## Sets the [member duration] value. +func set_duration(value: float) -> void: + duration = value + if duration == 0: + duration = 0.001 + +## Returns the [member duration] value. +func get_duration() -> float: + return duration + + +## Sets the [member decay_time] value. +func set_decay_time(value: float) -> void: + decay_time = value + +## Returns the [member decay_time] value. +func get_decay_time() -> float: + return decay_time + + +## Sets the [member noise_emitter_layer] value. +func set_noise_emitter_layer(value: int) -> void: + noise_emitter_layer = value + +## Enables or disables a given layer of [member noise_emitter_layer]. +func set_noise_emitter_value(value: int, enabled: bool) -> void: + noise_emitter_layer = _set_layer(noise_emitter_layer, value, enabled) + +## Returns the [member noise_emitter_layer] value. +func get_noise_emitter_layer() -> int: + return noise_emitter_layer + +#endregion diff --git a/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_3d.gd b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_3d.gd new file mode 100644 index 0000000..cd6c634 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera/phantom_camera_noise_emitter_3d.gd @@ -0,0 +1,265 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_noise_emitter_3d.svg") +class_name PhantomCameraNoiseEmitter3D +extends Node3D + +## Emits positional and rotational noise to active [PhantomCamera3D]s and its corresponding [Camera3D]. +## +## Is a node meant to apply positional and rotational noise, also referred to as shake, to the [Camera3D]. +## It is designed for use cases such as when hitting or when being hit, earthquakes or to add a +## bit of slight movement to the camera to make it feel less static. +## The emitter can affect multiple [PhantomCamera3D] in a given scene based on which [member noise_emitter_layer] +## are enabled by calling its [method emit] function. At least one corresponding layer has to be +## set on the [PhantomCamera3D] and the emitter node. + +const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +#region Exported Properties + +## The [PhantomCameraNoise3D] resource that defines the noise pattern. +@export var noise: PhantomCameraNoise3D = null: + set = set_noise, + get = get_noise + +## If true, previews the noise in the Viewfinder. +@export var preview: bool = false: + set(value): + preview = value + _play = value + get: + return preview + +## If true, repeats the noise indefinitely once started.Otherwise, it will only be triggered once. [br] +## [b]Note:[/b] This will always be enabled if the resource is assigned the the [PhantomCamera3D]'s +## [member PhantomCamera3D.noise] property. +@export var continuous: bool = false: + set = set_continuous, + get = get_continuous + +## Determines how long the noise should take to reach full [member intensity] once started.[br] +## The value is set in [b]seconds[/b]. +@export_exp_easing("positive_only", "suffix: s") var growth_time: float = 0: + set = set_growth_time, + get = get_growth_time + +## Sets the duration for the camera noise if [member loop] is set to false.[br] +## If the duration is [param 0] then [member continous] becomes enabled.[br] +## The value is set in [b]seconds[/b]. +@export_range(0, 10, 0.001, "or_greater", "suffix: s") var duration: float = 1.0: + set = set_duration, + get = get_duration + +## Determines how long the noise should take to come to a full stop.[br] +## The value is set in [b]seconds[/b]. +@export_exp_easing("attenuation", "positive_only", "suffix: s") var decay_time: float = 0: + set = set_decay_time, + get = get_decay_time + +## Enabled layers will affect [PhantomCamera3D] nodes with at least one corresponding layer enabled.[br] +## Enabling multiple corresponding layers on the same [PhantomCamera3D] causes no additional effect. +@export_flags_3d_render var noise_emitter_layer: int = 1: + set = set_noise_emitter_layer, + get = get_noise_emitter_layer + +#endregion + +#region Private Variables + +var _play: bool = false: + set(value): + _play = value + if value: + _elasped_play_time = 0 + _decay_countdown = 0 + _play = true + _should_grow = true + _start_duration_countdown = false + _should_decay = false + else: + _should_decay = true + if noise.randomize_noise_seed: + noise.noise_seed = randi() & 1000 + else: + noise.reset_noise_time() + get: + return _play + +var _start_duration_countdown: bool = false + +var _decay_countdown: float = 0 + +var _should_grow: bool = false + +var _should_decay: bool = false + +var _elasped_play_time: float = 0 + +var _noise_output: Transform3D = Transform3D() + +# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box. +var _phantom_camera_manager: Node + +#endregion + +#region Private Functions + +func _get_configuration_warnings() -> PackedStringArray: + if noise == null: + return ["Noise resource is required in order to trigger emitter."] + else: + return [] + + +func _validate_property(property) -> void: + if property.name == "duration" and continuous: + property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _enter_tree() -> void: + _phantom_camera_manager = get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME) + + +func _process(delta: float) -> void: + if not _play and not _should_decay: return + if noise == null: + printerr("Noise resource missing in ", name) + _play = false + return + + _elasped_play_time += delta + + if _should_grow: + noise.set_trauma(minf(_elasped_play_time / growth_time, 1)) + if _elasped_play_time >= growth_time: + _should_grow = false + _start_duration_countdown = true + noise.set_trauma(1) + + if not continuous: + if _start_duration_countdown: + if _elasped_play_time >= duration + growth_time: + _should_decay = true + _start_duration_countdown = false + + if _should_decay: + _decay_countdown += delta + noise.set_trauma(maxf(1 - (_decay_countdown / decay_time), 0)) + if _decay_countdown >= decay_time: + noise.set_trauma(0) + _play = false + preview = false + _should_decay = false + _elasped_play_time = 0 + _decay_countdown = 0 + + _noise_output = noise.get_noise_transform(delta) + _phantom_camera_manager.noise_3d_emitted.emit(_noise_output, noise_emitter_layer) + + +func _set_layer(current_layers: int, layer_number: int, value: bool) -> int: + var mask: int = current_layers + + # From https://github.com/godotengine/godot/blob/51991e20143a39e9ef0107163eaf283ca0a761ea/scene/3d/camera_3d.cpp#L638 + if layer_number < 1 or layer_number > 20: + printerr("Layer must be between 1 and 20.") + else: + if value: + mask |= 1 << (layer_number - 1) + else: + mask &= ~(1 << (layer_number - 1)) + + return mask + +#endregion + +#region Public Functions + +## Emits noise to the [PhantomCamera3D]s that has at least one matching layers. +func emit() -> void: + if _play: _play = false + _play = true + + +## Returns the state for the emitter. If true, the emitter is currently emitting. +func is_emitting() -> bool: + return _play + + +## Stops the emitter from emitting noise. +func stop(should_decay: bool = true) -> void: + if should_decay: + _should_decay = true + else: + _play = false + + +## Toggles the emitter on and off.[br] +func toggle() -> void: + _play = !_play + +#endregion + +#region Setter & Getter Functions + +## Sets the [member noise] resource. +func set_noise(value: PhantomCameraNoise3D) -> void: + noise = value + update_configuration_warnings() + +## Returns the [member noise] resource. +func get_noise() -> PhantomCameraNoise3D: + return noise + + +## Sets the [member continous] value. +func set_continuous(value: bool) -> void: + continuous = value + notify_property_list_changed() + +## Gets the [member continous] value. +func get_continuous() -> bool: + return continuous + + +## Sets the [member growth_time] value. +func set_growth_time(value: float) -> void: + growth_time = value + +## Returns the [member growth_time] value. +func get_growth_time() -> float: + return growth_time + + +## Sets the [member duration] value. +func set_duration(value: float) -> void: + duration = value + if duration == 0: + duration = 0.001 + +## Returns the [member duration] value. +func get_duration() -> float: + return duration + + +## Sets the [member decay_time] value. +func set_decay_time(value: float) -> void: + decay_time = value + +## Returns the [member decay_time] value. +func get_decay_time() -> float: + return decay_time + + +## Sets the [member noise_emitter_layer] value. +func set_noise_emitter_layer(value: int) -> void: + noise_emitter_layer = value + +## Enables or disables a given layer of [member noise_emitter_layer]. +func set_noise_emitter_value(value: int, enabled: bool) -> void: + noise_emitter_layer = _set_layer(noise_emitter_layer, value, enabled) + +## Returns the [member noise_emitter_layer] value. +func get_noise_emitter_layer() -> int: + return noise_emitter_layer + + #endregion diff --git a/godot/addons/phantom_camera/scripts/phantom_camera_host/PhantomCameraHost.cs b/godot/addons/phantom_camera/scripts/phantom_camera_host/PhantomCameraHost.cs new file mode 100644 index 0000000..99555f5 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera_host/PhantomCameraHost.cs @@ -0,0 +1,122 @@ +using Godot; + +#nullable enable + +namespace PhantomCamera; + +// public enum InterpolationMode +// { +// Auto, +// Idle, +// Physics +// } + +public static class PhantomCameraHostExtensions +{ + public static PhantomCameraHost AsPhantomCameraHost(this Node node) + { + return new PhantomCameraHost(node); + } +} + +public class PhantomCameraHost() +{ + public Node Node { get; } = null!; + + public PhantomCameraHost(Node node) : this() + { + Node = node; + + _callablePCamBecameActive = Callable.From(pCam => PCamBecameActive?.Invoke(pCam)); + _callablePCamBecameInactive = Callable.From(pCam => PCamBecameInactive?.Invoke(pCam)); + + Node.Connect(SignalName.PCamBecameActive, _callablePCamBecameActive); + Node.Connect(SignalName.PCamBecameInactive, _callablePCamBecameInactive); + } + + ~PhantomCameraHost() + { + Node.Disconnect(SignalName.PCamBecameActive, _callablePCamBecameActive); + Node.Disconnect(SignalName.PCamBecameInactive, _callablePCamBecameInactive); + } + + public delegate void PCamBecameActiveEventHandler(Node pCam); + public delegate void PCamBecameInactiveEventHandler(Node pCam); + + public event PCamBecameActiveEventHandler? PCamBecameActive; + public event PCamBecameInactiveEventHandler? PCamBecameInactive; + + + private readonly Callable _callablePCamBecameActive; + private readonly Callable _callablePCamBecameInactive; + // For when Godot becomes the minimum version + // public InterpolationMode InterpolationMode + // { + // get => (InterpolationMode)(int)Node.Call(MethodName.GetInterpolationMode); + // set => Node.Call(MethodName.SetInterpolationMode, (int)value); + // } + + public int HostLayers + { + get => (int)Node.Call(PhantomCamera.MethodName.GetHostLayers); + set => Node.Call(PhantomCamera.MethodName.SetHostLayers, value); + } + + public void SetHostLayersValue(int layer, bool value) => Node.Call(MethodName.SetHostLayersValue, layer, value); + + public Camera2D? Camera2D => (Camera2D?)Node.Get(PropertyName.Camera2D); + + public Camera3D? Camera3D => (Camera3D?)Node.Get(PropertyName.Camera3D); + + public bool TriggerPhantomCameraTween => (bool)Node.Call(MethodName.GetTriggerPhantomCameraTween); + + public ActivePhantomCameraQueryResult? GetActivePhantomCamera() + { + var result = Node.Call(MethodName.GetActivePhantomCamera); + return result.VariantType == Variant.Type.Nil ? null : new ActivePhantomCameraQueryResult(result.AsGodotObject()); + } + + public static class PropertyName + { + public const string Camera2D = "camera_2d"; + public const string Camera3D = "camera_3d"; + } + + public static class MethodName + { + public const string GetActivePhantomCamera = "get_active_pcam"; + public const string GetTriggerPhantomCameraTween = "get_trigger_pcam_tween"; + + public const string GetInterpolationMode = "get_interpolation_mode"; + public const string SetInterpolationMode = "set_interpolation_mode"; + + public const string SetHostLayersValue = "set_host_layers_value"; + } + + public static class SignalName + { + public const string PCamBecameActive = "pcam_became_active"; + public const string PCamBecameInactive = "pcam_became_inactive"; + } +} + +public class ActivePhantomCameraQueryResult(GodotObject godotObject) +{ + public bool Is2D => godotObject.IsClass("Node2D") || ((Node)godotObject).Name.ToString().Contains("PhantomCamera2D") + || ((Node)godotObject).Name.ToString().Contains("PCam2D") + || ((Node)godotObject).Name.ToString().Contains("2D"); + + public bool Is3D => godotObject.IsClass("Node3D") || ((Node)godotObject).Name.ToString().Contains("PhantomCamera3D") + || ((Node)godotObject).Name.ToString().Contains("PCam3D") + || ((Node)godotObject).Name.ToString().Contains("3D"); + + public PhantomCamera2D? AsPhantomCamera2D() + { + return Is2D ? new PhantomCamera2D(godotObject) : null; + } + + public PhantomCamera3D? AsPhantomCamera3D() + { + return Is3D ? new PhantomCamera3D(godotObject) : null; + } +} diff --git a/godot/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd b/godot/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd new file mode 100644 index 0000000..d969dc2 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd @@ -0,0 +1,1437 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_host.svg") +class_name PhantomCameraHost +extends Node + +## Controls a scene's [Camera2D] (2D scenes) and [Camera3D] (3D scenes). +## +## All instantiated [param PhantomCameras] in a scene are assigned to a specific layer, where a +## PhantomCameraHost will react to those that corresponds. It is what determines which [param PhantomCamera] should +## be active. + +#region Signals + + +#endregion + +#region Constants + +const _constants := preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd") + +#endregion + +#region Signals + +## Updates the viewfinder [param dead zones] sizes.[br] +## [b]Note:[/b] This is only being used in the editor viewfinder UI. +#signal update_editor_viewfinder +signal viewfinder_update(check_framed_view: bool) +signal viewfinder_disable_dead_zone + +## Used internally to check if the [param PhantomCameraHost] is valid. +## The result will be visible in the viewfinder when multiple instances are present. +signal has_error() + +## Emitted when a new [param PhantomCamera] becomes active and assigned to this [param PhantomCameraHost]. +signal pcam_became_active(pcam: Node) + +## Emitted when an active [param PhantomCamera] becomes inactive. +signal pcam_became_inactive(pcam: Node) + +#endregion + + +#region Enums + +enum InterpolationMode { + AUTO = 0, + IDLE = 1, + PHYSICS = 2, +} + +#endregion + + +#region Public Variables + +## Determines which [PhantomCamera2D] / [PhantomCamera3D] nodes this [param PhantomCameraHost] should recognise. +## At least one corresponding layer needs to be set on the [param PhantomCamera] for the [param PhantomCameraHost] node to work. +@export_flags_2d_render var host_layers: int = 1: + set = set_host_layers, + get = get_host_layers + +## TBD - For when Godot 4.3 becomes the minimum version +#@export var interpolation_mode: InterpolationMode = InterpolationMode.AUTO: + #set = set_interpolation_mode, + #get = get_interpolation_mode + +#endregion + + +#region Private Variables + +var _active_pcam_2d: PhantomCamera2D = null +var _active_pcam_3d: Node = null ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. +var _active_pcam_priority: int = -1 +var _active_pcam_missing: bool = true +var _active_pcam_has_damping: bool = false +var _follow_target_physics_based: bool = false + +var _prev_active_pcam_2d_transform: Transform2D = Transform2D() +var _prev_active_pcam_3d_transform: Transform3D = Transform3D() + +var _trigger_pcam_tween: bool = false +var _tween_elapsed_time: float = 0 +var _tween_duration: float = 0 +var _tween_is_instant: bool = false + +var _multiple_pcam_hosts: bool = false + +var _is_child_of_camera: bool = false +var _is_2d: bool = false + +var _viewfinder_node: Control = null +var _viewfinder_needed_check: bool = true + +var _camera_zoom: Vector2 = Vector2.ONE + +#region Camera3DResource + +var _prev_cam_attributes: CameraAttributes = null +var _cam_attribute_type: int = 0 # 0 = CameraAttributesPractical, 1 = CameraAttributesPhysical +var _cam_attribute_changed: bool = false +var _cam_attribute_assigned: bool = false + +#region CameraAttributes +var _prev_cam_auto_exposure_scale: float = 0.4 +var _cam_auto_exposure_scale_changed: bool = false + +var _prev_cam_auto_exposure_speed: float = 0.5 +var _cam_auto_exposure_speed_changed: bool = false + +var _prev_cam_exposure_multiplier: float = 1.0 +var _cam_exposure_multiplier_changed: bool = false + +var _prev_cam_exposure_sensitivity: float = 100.0 +var _cam_exposure_sensitivity_changed: bool = false + +#region CameraAttributesPractical +var _prev_cam_exposure_min_sensitivity: float = 0.0 +var _cam_exposure_min_sensitivity_changed: bool = false + +var _prev_cam_exposure_max_sensitivity: float = 800.0 +var _cam_exposure_max_sensitivity_changed: bool = false + +var _prev_cam_dof_blur_amount: float = 0.1 +var _cam_dof_blur_amount_changed: bool = false + +var _cam_dof_blur_far_distance_default: float = 10 +var _prev_cam_dof_blur_far_distance: float = _cam_dof_blur_far_distance_default +var _cam_dof_blur_far_distance_changed: bool = false + +var _cam_dof_blur_far_transition_default: float = 5 +var _prev_cam_dof_blur_far_transition: float = _cam_dof_blur_far_transition_default +var _cam_dof_blur_far_transition_changed: bool = false + +var _cam_dof_blur_near_distance_default: float = 2 +var _prev_cam_dof_blur_near_distance: float = _cam_dof_blur_near_distance_default +var _cam_dof_blur_near_distance_changed: bool = false + +var _cam_dof_blur_near_transition_default: float = 1 +var _prev_cam_dof_blur_near_transition: float = _cam_dof_blur_near_transition_default +var _cam_dof_blur_near_transition_changed: bool = false +#endregion + +#region CameraAttributesPhysical +var _prev_cam_exposure_min_exposure_value: float = 10.0 +var _cam_exposure_min_exposure_value_changed: bool = false + +var _prev_cam_exposure_max_exposure_value: float = -8.0 +var _cam_exposure_max_exposure_value_changed: bool = false + +var _prev_cam_exposure_aperture: float = 16.0 +var _cam_exposure_aperture_changed: bool = false + +var _prev_cam_exposure_shutter_speed: float = 100.0 +var _cam_exposure_shutter_speed_changed: bool = false + +var _prev_cam_frustum_far: float = 4000.0 +var _cam_frustum_far_changed: bool = false + +var _prev_cam_frustum_focal_length: float = 35.0 +var _cam_frustum_focal_length_changed: bool = false + +var _prev_cam_frustum_near: float = 0.05 +var _cam_frustum_near_changed: bool = false + +var _prev_cam_frustum_focus_distance: float = 10.0 +var _cam_frustum_focus_distance_changed: bool = false + +#endregion + +var _prev_cam_h_offset: float = 0 +var _cam_h_offset_changed: bool = false + +var _prev_cam_v_offset: float = 0 +var _cam_v_offset_changed: bool = false + +var _prev_cam_fov: float = 75 +var _cam_fov_changed: bool = false + +var _prev_cam_size: float = 1 +var _cam_size_changed: bool = false + +var _prev_cam_frustum_offset: Vector2 = Vector2.ZERO +var _cam_frustum_offset_changed: bool = false + +var _prev_cam_near: float = 0.05 +var _cam_near_changed: bool = false + +var _prev_cam_far: float = 4000 +var _cam_far_changed: bool = false + +#endregion + +var _active_pcam_2d_glob_transform: Transform2D = Transform2D() +var _active_pcam_3d_glob_transform: Transform3D = Transform3D() + +var _has_noise_emitted: bool = false +var _reset_noise_offset_2d: bool = false +var _noise_emitted_output_2d: Transform2D = Transform2D() +var _noise_emitted_output_3d: Transform3D = Transform3D() + +#endregion + +# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box. +var _phantom_camera_manager: Node = null + +#region Public Variables + +var show_warning: bool = false + +## For 2D scenes, is the [Camera2D] instance the [param PhantomCameraHost] controls. +var camera_2d: Camera2D = null + +## For 3D scenes, is the [Camera3D] instance the [param PhantomCameraHost] controls. +var camera_3d: Node = null ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + +#endregion + +#region Private Functions + +## TBD - For when Godot 4.3 becomes a minimum version +#func _validate_property(property: Dictionary) -> void: + #if property.name == "interpolation_mode" and get_parent() is Node3D: + #property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _get_configuration_warnings() -> PackedStringArray: + var parent: Node = get_parent() + var first_pcam_host_child: PhantomCameraHost + + if _is_2d: + if not parent is Camera2D: + show_warning = true + has_error.emit() + return["Needs to be a child of a Camera2D in order to work."] + else: + if not parent.is_class("Camera3D"): ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + show_warning = true + has_error.emit() + return["Needs to be a child of a Camera3D in order to work."] + + for child in parent.get_children(): + if not child is PhantomCameraHost: continue + if not is_instance_valid(first_pcam_host_child): + first_pcam_host_child = child + continue + elif not first_pcam_host_child == self: + show_warning = true + has_error.emit() + return["Only the first PhantomCameraHost child will be used."] + child.update_configuration_warnings() + + show_warning = false + has_error.emit() + return[] + + +func _enter_tree() -> void: + var parent: Node = get_parent() + if parent is Camera2D or parent.is_class("Camera3D"): ## Note: To support disable_3d export templates for 2D projects, this is purposely not strongly typed. + _phantom_camera_manager = get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME) + _phantom_camera_manager.pcam_host_added(self) + + _is_child_of_camera = true + if parent is Camera2D: + _is_2d = true + camera_2d = parent + ## Force applies position smoothing to be disabled + ## This is to prevent overlap with the interpolation of the PCam2D. + camera_2d.set_position_smoothing_enabled(false) + else: + _is_2d = false + camera_3d = parent + + if _is_2d: + if not _phantom_camera_manager.get_phantom_camera_2ds().is_empty(): + for pcam in _phantom_camera_manager.get_phantom_camera_2ds(): + _pcam_added_to_scene(pcam) + + if not _phantom_camera_manager.limit_2d_changed.is_connected(_update_limit_2d): + _phantom_camera_manager.limit_2d_changed.connect(_update_limit_2d) + if not _phantom_camera_manager.draw_limit_2d.is_connected(_draw_limit_2d): + _phantom_camera_manager.draw_limit_2d.connect(_draw_limit_2d) + + else: + if not _phantom_camera_manager.get_phantom_camera_3ds().is_empty(): + for pcam in _phantom_camera_manager.get_phantom_camera_3ds(): + _pcam_added_to_scene(pcam) + + +func _exit_tree() -> void: + if is_instance_valid(_phantom_camera_manager): + _phantom_camera_manager.pcam_host_removed(self) + + +func _ready() -> void: + # Waits for the first process tick to finish before initializing any logic + # This should help with avoiding ocassional erratic camera movement upon running a scene + await get_tree().process_frame + + process_priority = 300 + process_physics_priority = 300 + + # PCam Host Signals + if Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): + _phantom_camera_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME) + _phantom_camera_manager.pcam_host_layer_changed.connect(_pcam_host_layer_changed) + + # PCam Signals + _phantom_camera_manager.pcam_added_to_scene.connect(_pcam_added_to_scene) + _phantom_camera_manager.pcam_removed_from_scene.connect(_pcam_removed_from_scene) + + _phantom_camera_manager.pcam_priority_changed.connect(pcam_priority_updated) + _phantom_camera_manager.pcam_priority_override.connect(_pcam_priority_override) + + _phantom_camera_manager.pcam_visibility_changed.connect(_pcam_visibility_changed) + + _phantom_camera_manager.pcam_teleport.connect(_pcam_teleported) + + if _is_2d: + if not _phantom_camera_manager.limit_2d_changed.is_connected(_update_limit_2d): + _phantom_camera_manager.limit_2d_changed.connect(_update_limit_2d) + if not _phantom_camera_manager.draw_limit_2d.is_connected(_draw_limit_2d): + _phantom_camera_manager.draw_limit_2d.connect(_draw_limit_2d) + else: + printerr("Could not find Phantom Camera Manager singleton") + printerr("Make sure the addon is enable or that the singleton hasn't been disabled inside Project Settings / Globals") + + _find_pcam_with_highest_priority() + + if _is_2d: + camera_2d.offset = Vector2.ZERO + if not is_instance_valid(_active_pcam_2d): return + _active_pcam_2d_glob_transform = _active_pcam_2d.get_transform_output() + else: + if not is_instance_valid(_active_pcam_3d): return + _active_pcam_3d_glob_transform = _active_pcam_3d.get_transform_output() + + +func _pcam_host_layer_changed(pcam: Node) -> void: + if _pcam_is_in_host_layer(pcam): + _check_pcam_priority(pcam) + else: + if _is_2d: + if _active_pcam_2d == pcam: + _active_pcam_missing = true + _active_pcam_2d = null + _active_pcam_priority = -1 + pcam.set_is_active(self, false) + else: + if _active_pcam_3d == pcam: + _active_pcam_missing = true + _active_pcam_3d = null + _active_pcam_priority = -1 + pcam.set_is_active(self, false) + _find_pcam_with_highest_priority() + + +func _pcam_is_in_host_layer(pcam: Node) -> bool: + if pcam.host_layers & host_layers != 0: return true + return false + + +func _find_pcam_with_highest_priority() -> void: + var pcam_list: Array + if _is_2d: + pcam_list = _phantom_camera_manager.phantom_camera_2ds + else: + pcam_list = _phantom_camera_manager.phantom_camera_3ds + + for pcam in pcam_list: + _check_pcam_priority(pcam) + + +func _check_pcam_priority(pcam: Node) -> void: + if not _pcam_is_in_host_layer(pcam): return + if not pcam.visible: return # Prevents hidden PCams from becoming active + if pcam.get_priority() > _active_pcam_priority: + _assign_new_active_pcam(pcam) + _active_pcam_missing = false + else: + pcam.set_tween_skip(self, false) + + +func _assign_new_active_pcam(pcam: Node) -> void: + # Only checks if the scene tree is still present. + # Prevents a few errors and checks from happening if the scene is exited. + if not is_inside_tree(): return + var no_previous_pcam: bool + if is_instance_valid(_active_pcam_2d) or is_instance_valid(_active_pcam_3d): + if OS.has_feature("debug"): + viewfinder_disable_dead_zone.emit() + + if _is_2d: + _prev_active_pcam_2d_transform = camera_2d.global_transform + _active_pcam_2d.queue_redraw() + _active_pcam_2d.set_is_active(self, false) + _active_pcam_2d.became_inactive.emit() + pcam_became_inactive.emit(_active_pcam_2d) + + if _active_pcam_2d.physics_target_changed.is_connected(_check_pcam_physics): + _active_pcam_2d.physics_target_changed.disconnect(_check_pcam_physics) + + if _active_pcam_2d.noise_emitted.is_connected(_noise_emitted_2d): + _active_pcam_2d.noise_emitted.disconnect(_noise_emitted_2d) + + if _trigger_pcam_tween: + _active_pcam_2d.tween_interrupted.emit(pcam) + else: + _prev_active_pcam_3d_transform = camera_3d.global_transform + _active_pcam_3d.set_is_active(self, false) + _active_pcam_3d.became_inactive.emit() + pcam_became_inactive.emit(_active_pcam_3d) + + if _active_pcam_3d.physics_target_changed.is_connected(_check_pcam_physics): + _active_pcam_3d.physics_target_changed.disconnect(_check_pcam_physics) + + if _active_pcam_3d.noise_emitted.is_connected(_noise_emitted_3d): + _active_pcam_3d.noise_emitted.disconnect(_noise_emitted_3d) + + if _active_pcam_3d.camera_3d_resource_changed.is_connected(_camera_3d_resource_changed): + _active_pcam_3d.camera_3d_resource_changed.disconnect(_camera_3d_resource_changed) + + if _active_pcam_3d.camera_3d_resource_property_changed.is_connected(_camera_3d_resource_property_changed): + _active_pcam_3d.camera_3d_resource_property_changed.disconnect(_camera_3d_resource_property_changed) + + if _trigger_pcam_tween: + _active_pcam_3d.tween_interrupted.emit(pcam) + + if camera_3d.attributes != null: + var _attributes: CameraAttributes = camera_3d.attributes + + _prev_cam_exposure_multiplier = _attributes.exposure_multiplier + _prev_cam_auto_exposure_scale = _attributes.auto_exposure_scale + _prev_cam_auto_exposure_speed = _attributes.auto_exposure_speed + + if camera_3d.attributes is CameraAttributesPractical: + _attributes = _attributes as CameraAttributesPractical + + _prev_cam_dof_blur_amount = _attributes.dof_blur_amount + + if _attributes.dof_blur_far_enabled: + _prev_cam_dof_blur_far_distance = _attributes.dof_blur_far_distance + _prev_cam_dof_blur_far_transition = _attributes.dof_blur_far_transition + else: + _prev_cam_dof_blur_far_distance = _cam_dof_blur_far_distance_default + _prev_cam_dof_blur_far_transition = _cam_dof_blur_far_transition_default + + if _attributes.dof_blur_near_enabled: + _prev_cam_dof_blur_near_distance = _attributes.dof_blur_near_distance + _prev_cam_dof_blur_near_transition = _attributes.dof_blur_near_transition + else: + _prev_cam_dof_blur_near_distance = _cam_dof_blur_near_distance_default + _prev_cam_dof_blur_near_transition = _cam_dof_blur_near_transition_default + + if _attributes.auto_exposure_enabled: + _prev_cam_exposure_max_sensitivity = _attributes.auto_exposure_max_sensitivity + _prev_cam_exposure_min_sensitivity = _attributes.auto_exposure_min_sensitivity + + elif camera_3d.attributes is CameraAttributesPhysical: + _attributes = _attributes as CameraAttributesPhysical + + _prev_cam_frustum_focus_distance = _attributes.frustum_focus_distance + _prev_cam_frustum_focal_length = _attributes.frustum_focal_length + _prev_cam_frustum_far = _attributes.frustum_far + _prev_cam_frustum_near = _attributes.frustum_near + _prev_cam_exposure_aperture = _attributes.exposure_aperture + _prev_cam_exposure_shutter_speed = _attributes.exposure_shutter_speed + + if _attributes.auto_exposure_enabled: + _prev_cam_exposure_min_exposure_value = _attributes.auto_exposure_min_exposure_value + _prev_cam_exposure_max_exposure_value = _attributes.auto_exposure_max_exposure_value + + _prev_cam_h_offset = camera_3d.h_offset + _prev_cam_v_offset = camera_3d.v_offset + _prev_cam_fov = camera_3d.fov + _prev_cam_size = camera_3d.size + _prev_cam_frustum_offset = camera_3d.frustum_offset + _prev_cam_near = camera_3d.near + _prev_cam_far = camera_3d.far + + else: + no_previous_pcam = true + + ## Assign newly active pcam + if _is_2d: + _active_pcam_2d = pcam + _active_pcam_priority = _active_pcam_2d.priority + _active_pcam_has_damping = _active_pcam_2d.follow_damping + _tween_duration = _active_pcam_2d.tween_duration + + if not _active_pcam_2d.physics_target_changed.is_connected(_check_pcam_physics): + _active_pcam_2d.physics_target_changed.connect(_check_pcam_physics) + + if not _active_pcam_2d.noise_emitted.is_connected(_noise_emitted_2d): + _active_pcam_2d.noise_emitted.connect(_noise_emitted_2d) + else: + _active_pcam_3d = pcam + _active_pcam_priority = _active_pcam_3d.priority + _active_pcam_has_damping = _active_pcam_3d.follow_damping + _tween_duration = _active_pcam_3d.tween_duration + + if not Engine.is_editor_hint(): + # Assigns a default shape to SpringArm3D node is none is supplied + if _active_pcam_3d.follow_mode == _active_pcam_3d.FollowMode.THIRD_PERSON: + if not _active_pcam_3d.shape: + + var pyramid_shape_data = Engine.get_singleton("PhysicsServer3D").call("shape_get_data", + camera_3d.get_pyramid_shape_rid() + ) + var shape = ClassDB.instantiate("ConvexPolygonShape3D") + shape.points = pyramid_shape_data + _active_pcam_3d.shape = shape + + if not _active_pcam_3d.physics_target_changed.is_connected(_check_pcam_physics): + _active_pcam_3d.physics_target_changed.connect(_check_pcam_physics) + + if not _active_pcam_3d.noise_emitted.is_connected(_noise_emitted_3d): + _active_pcam_3d.noise_emitted.connect(_noise_emitted_3d) + + if not _active_pcam_3d.camera_3d_resource_changed.is_connected(_camera_3d_resource_changed): + _active_pcam_3d.camera_3d_resource_changed.connect(_camera_3d_resource_changed) + + if not _active_pcam_3d.camera_3d_resource_property_changed.is_connected(_camera_3d_resource_property_changed): + _active_pcam_3d.camera_3d_resource_property_changed.connect(_camera_3d_resource_property_changed) + + # Checks if the Camera3DResource has changed from the previous active PCam3D + if _active_pcam_3d.camera_3d_resource: + # Signal to detect if the Camera3D properties are being changed in the inspector + # This is to prevent accidential misalignment between the Camera3D and Camera3DResource + if Engine.is_editor_hint(): + if not Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.is_connected(_camera_3d_edited): + Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.connect(_camera_3d_edited) + if _prev_cam_h_offset != _active_pcam_3d.h_offset: + _cam_h_offset_changed = true + if _prev_cam_v_offset != _active_pcam_3d.v_offset: + _cam_v_offset_changed = true + if _prev_cam_fov != _active_pcam_3d.fov: + _cam_fov_changed = true + if _prev_cam_size != _active_pcam_3d.size: + _cam_size_changed = true + if _prev_cam_frustum_offset != _active_pcam_3d.frustum_offset: + _cam_frustum_offset_changed = true + if _prev_cam_near != _active_pcam_3d.near: + _cam_near_changed = true + if _prev_cam_far != _active_pcam_3d.far: + _cam_far_changed = true + else: + _cam_h_offset_changed = false + _cam_v_offset_changed = false + _cam_fov_changed = false + _cam_size_changed = false + _cam_frustum_offset_changed = false + _cam_near_changed = false + _cam_far_changed = false + _cam_attribute_changed = false + if Engine.is_editor_hint(): + if Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.is_connected(_camera_3d_edited): + Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.disconnect(_camera_3d_edited) + + if _active_pcam_3d.attributes == null: + _cam_attribute_changed = false + else: + if _prev_cam_attributes != _active_pcam_3d.attributes: + _prev_cam_attributes = _active_pcam_3d.attributes + _cam_attribute_changed = true + var _attributes: CameraAttributes = _active_pcam_3d.attributes + + if _prev_cam_auto_exposure_scale != _attributes.auto_exposure_scale: + _cam_auto_exposure_scale_changed = true + if _prev_cam_auto_exposure_speed != _attributes.auto_exposure_speed: + _cam_auto_exposure_speed_changed = true + if _prev_cam_exposure_multiplier != _attributes.exposure_multiplier: + _cam_exposure_multiplier_changed = true + if _prev_cam_exposure_sensitivity != _attributes.exposure_sensitivity: + _cam_exposure_sensitivity_changed = true + + if _attributes is CameraAttributesPractical: + _cam_attribute_type = 0 + + if camera_3d.attributes == null: + camera_3d.attributes = CameraAttributesPractical.new() + camera_3d.attributes = _active_pcam_3d.attributes.duplicate() + _cam_attribute_assigned = true + + if _prev_cam_exposure_min_sensitivity != _attributes.auto_exposure_min_sensitivity: + _cam_exposure_min_sensitivity_changed = true + if _prev_cam_exposure_max_sensitivity != _attributes.auto_exposure_max_sensitivity: + _cam_exposure_max_sensitivity_changed = true + + if _prev_cam_dof_blur_amount != _attributes.dof_blur_amount: + _cam_dof_blur_amount_changed = true + + if _prev_cam_dof_blur_far_distance != _attributes.dof_blur_far_distance: + _cam_dof_blur_far_distance_changed = true + camera_3d.attributes.dof_blur_far_enabled = true + if _prev_cam_dof_blur_far_transition != _attributes.dof_blur_far_transition: + _cam_dof_blur_far_transition_changed = true + camera_3d.attributes.dof_blur_far_enabled = true + + if _prev_cam_dof_blur_near_distance != _attributes.dof_blur_near_distance: + _cam_dof_blur_near_distance_changed = true + camera_3d.attributes.dof_blur_near_enabled = true + if _prev_cam_dof_blur_near_transition != _attributes.dof_blur_near_transition: + _cam_dof_blur_near_transition_changed = true + camera_3d.attributes.dof_blur_near_enabled = true + elif _attributes is CameraAttributesPhysical: + _cam_attribute_type = 1 + + if camera_3d.attributes == null: + camera_3d.attributes = CameraAttributesPhysical.new() + camera_3d.attributes = _active_pcam_3d.attributes.duplicate() + + if _prev_cam_exposure_min_exposure_value != _attributes.auto_exposure_min_exposure_value: + _cam_exposure_min_exposure_value_changed = true + if _prev_cam_exposure_max_exposure_value != _attributes.auto_exposure_max_exposure_value: + _cam_exposure_max_exposure_value_changed = true + + if _prev_cam_exposure_aperture != _attributes.exposure_aperture: + _cam_exposure_aperture_changed = true + if _prev_cam_exposure_shutter_speed != _attributes.exposure_shutter_speed: + _cam_exposure_shutter_speed_changed = true + + if _prev_cam_frustum_far != _attributes.frustum_far: + _cam_frustum_far_changed = true + + if _prev_cam_frustum_focal_length != _attributes.frustum_focal_length: + _cam_frustum_focal_length_changed = true + + if _prev_cam_frustum_focus_distance != _attributes.frustum_focus_distance: + _cam_frustum_focus_distance_changed = true + + if _prev_cam_frustum_near != _attributes.frustum_near: + _cam_frustum_near_changed = true + + if OS.has_feature("debug"): + viewfinder_update.emit(false) + + if _is_2d: + if _active_pcam_2d.show_viewfinder_in_play: + _viewfinder_needed_check = true + + _active_pcam_2d.set_is_active(self, true) + _active_pcam_2d.became_active.emit() + pcam_became_active.emit(_active_pcam_2d) + _camera_zoom = camera_2d.zoom + else: + if _active_pcam_3d.show_viewfinder_in_play: + _viewfinder_needed_check = true + + _active_pcam_3d.set_is_active(self, true) + _active_pcam_3d.became_active.emit() + pcam_became_active.emit(_active_pcam_3d) + if _active_pcam_3d.camera_3d_resource: + camera_3d.keep_aspect = _active_pcam_3d.keep_aspect + camera_3d.cull_mask = _active_pcam_3d.cull_mask + camera_3d.projection = _active_pcam_3d.projection + + if no_previous_pcam: + if _is_2d: + _prev_active_pcam_2d_transform = _active_pcam_2d.get_transform_output() + else: + _prev_active_pcam_3d_transform = _active_pcam_3d.get_transform_output() + + if pcam.get_tween_skip() or pcam.tween_duration == 0: + _tween_elapsed_time = pcam.tween_duration + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor >= 3: + _tween_is_instant = true + else: + _tween_elapsed_time = 0 + + _check_pcam_physics() + + _trigger_pcam_tween = true + + +func _check_pcam_physics() -> void: + if _is_2d: + ## NOTE - Only supported in Godot 4.3 or later + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor >= 3: + if _active_pcam_2d.get_follow_target_physics_based(): + _follow_target_physics_based = true + ## TODO - Temporary solution to support Godot 4.2 + ## Remove line below and uncomment the following once Godot 4.3 is min verison. + camera_2d.call("reset_physics_interpolation") + camera_2d.set("physics_interpolation_mode", 1) + #camera_2d.reset_physics_interpolation() + #camera_2d.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_ON + if ProjectSettings.get_setting("physics/common/physics_interpolation"): + camera_2d.process_callback = Camera2D.CAMERA2D_PROCESS_PHYSICS # Prevents a warning + else: + camera_2d.process_callback = Camera2D.CAMERA2D_PROCESS_IDLE + else: + _follow_target_physics_based = false + ## TODO - Temporary solution to support Godot 4.2 + ## Remove line below and uncomment the following once Godot 4.3 is min verison. + camera_2d.set("physics_interpolation_mode", 0) + #camera_2d.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_INHERIT + if get_tree().physics_interpolation: + camera_2d.process_callback = Camera2D.CAMERA2D_PROCESS_PHYSICS # Prevents a warning + else: + camera_2d.process_callback = Camera2D.CAMERA2D_PROCESS_IDLE + else: + ## NOTE - Only supported in Godot 4.4 or later + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor >= 4: + if get_tree().physics_interpolation or _active_pcam_3d.get_follow_target_physics_based(): + #if get_tree().physics_interpolation or _active_pcam_3d.get_follow_target_physics_based(): + _follow_target_physics_based = true + ## TODO - Temporary solution to support Godot 4.2 + ## Remove line below and uncomment the following once Godot 4.3 is min verison. + camera_3d.call("reset_physics_interpolation") + camera_3d.set("physics_interpolation_mode", 1) + #camera_3d.reset_physics_interpolation() + #camera_3d.physics_interpolation_mode = Node.PHYSICS_INTERPOLATION_MODE_ON + else: + _follow_target_physics_based = false + ## TODO - Temporary solution to support Godot 4.2 + ## Remove line below and uncomment the following once Godot 4.3 is min verison. + camera_3d.set("physics_interpolation_mode", 0) + + +## TODO - For 0.8 release +#func _find_pcam_with_highest_priority() -> void: + #var highest_priority_pcam: Node + #for pcam in _pcam_list: + #if not pcam.visible: continue # Prevents hidden PCams from becoming active + #if pcam.priority > _active_pcam_priority: + #_active_pcam_priority = pcam.priority + #highest_priority_pcam = pcam + #pcam.set_has_tweened(self, false) +# + #_active_pcam_missing = false +# + #if is_instance_valid(highest_priority_pcam): + #_assign_new_active_pcam(highest_priority_pcam) + #else: + #_active_pcam_missing = true + + +func _process(delta: float) -> void: + if _active_pcam_missing: return + + if not _follow_target_physics_based: _tween_follow_checker(delta) + + +func _physics_process(delta: float) -> void: + if _active_pcam_missing or not _follow_target_physics_based: return + _tween_follow_checker(delta) + + +func _tween_follow_checker(delta: float) -> void: + if _is_2d: + if not is_instance_valid(_active_pcam_2d): + _active_pcam_missing = true + return + + _active_pcam_2d.process_logic(delta) + _active_pcam_2d_glob_transform = _active_pcam_2d.get_transform_output() + + if _reset_noise_offset_2d: + camera_2d.offset = Vector2.ZERO # Resets noise position + _reset_noise_offset_2d = false + else: + if not is_instance_valid(_active_pcam_3d): + _active_pcam_missing = true + return + + _active_pcam_3d.process_logic(delta) + _active_pcam_3d_glob_transform = _active_pcam_3d.get_transform_output() + + if not _trigger_pcam_tween: + # Rechecks physics target if PCam transitioned with an instant tween + if _tween_is_instant: + _check_pcam_physics() + _tween_is_instant = false + _pcam_follow(delta) + else: + _pcam_tween(delta) + + # Camera Noise + if _is_2d: + if not _has_noise_emitted and not _active_pcam_2d.has_noise_resource(): return + camera_2d.offset += _active_pcam_2d.get_noise_transform().origin + _noise_emitted_output_2d.origin + if camera_2d.ignore_rotation and _noise_emitted_output_2d.get_rotation() != 0: + push_warning(camera_2d.name, " has ignore_rotation enabled. Uncheck the property if you want to apply rotational noise.") + else: + camera_2d.rotation += _active_pcam_2d.get_noise_transform().get_rotation() + _noise_emitted_output_2d.get_rotation() + _has_noise_emitted = false + _reset_noise_offset_2d = true + else: + if not _has_noise_emitted and not _active_pcam_3d.has_noise_resource(): return + camera_3d.global_transform *= _active_pcam_3d.get_noise_transform() * _noise_emitted_output_3d + _has_noise_emitted = false + + +func _pcam_follow(_delta: float) -> void: + if _active_pcam_missing or not _is_child_of_camera: return + + if _is_2d: + if _active_pcam_2d.snap_to_pixel: + var snap_to_pixel_glob_transform: Transform2D = _active_pcam_2d_glob_transform + snap_to_pixel_glob_transform.origin = snap_to_pixel_glob_transform.origin.round() + camera_2d.global_transform = snap_to_pixel_glob_transform + else: + camera_2d.global_transform = _active_pcam_2d_glob_transform + camera_2d.zoom = _active_pcam_2d.zoom + else: + camera_3d.global_transform = _active_pcam_3d_glob_transform + + if _viewfinder_needed_check: + _show_viewfinder_in_play() + _viewfinder_needed_check = false + + if Engine.is_editor_hint(): + if not _is_2d: + # TODO - Signal-based solution pending merge of: https://github.com/godotengine/godot/pull/99729 + if _active_pcam_3d.attributes != null: + camera_3d.attributes = _active_pcam_3d.attributes.duplicate() + + # TODO - Signal-based solution pending merge of: https://github.com/godotengine/godot/pull/99873 + if _active_pcam_3d.environment != null: + camera_3d.environment = _active_pcam_3d.environment.duplicate() + + +func _noise_emitted_2d(noise_output: Transform2D) -> void: + _noise_emitted_output_2d = noise_output + _has_noise_emitted = true + + +func _noise_emitted_3d(noise_output: Transform3D) -> void: + _noise_emitted_output_3d = noise_output + _has_noise_emitted = true + + +func _camera_3d_resource_changed() -> void: + if _active_pcam_3d.camera_3d_resource: + if Engine.is_editor_hint(): + if not Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.is_connected(_camera_3d_edited): + Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.connect(_camera_3d_edited) + camera_3d.keep_aspect = _active_pcam_3d.keep_aspect + camera_3d.cull_mask = _active_pcam_3d.cull_mask + camera_3d.h_offset = _active_pcam_3d.h_offset + camera_3d.v_offset = _active_pcam_3d.v_offset + camera_3d.projection = _active_pcam_3d.projection + camera_3d.fov = _active_pcam_3d.fov + camera_3d.size = _active_pcam_3d.size + camera_3d.frustum_offset = _active_pcam_3d.frustum_offset + camera_3d.near = _active_pcam_3d.near + camera_3d.far = _active_pcam_3d.far + else: + if Engine.is_editor_hint(): + if Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.is_connected(_camera_3d_edited): + Engine.get_singleton(&"EditorInterface").get_inspector().property_edited.disconnect(_camera_3d_edited) + +func _camera_3d_edited(value: String) -> void: + if not Engine.get_singleton(&"EditorInterface").get_inspector().get_edited_object() == camera_3d: return + camera_3d.set(value, _active_pcam_3d.camera_3d_resource.get(value)) + push_warning("Camera3D properties are being overridden by ", _active_pcam_3d.name, "'s Camera3DResource") + +func _camera_3d_resource_property_changed(property: StringName, value: Variant) -> void: + camera_3d.set(property, value) + + +func _pcam_tween(delta: float) -> void: + # TODO - Should be optimised + # Run at the first tween frame + if _tween_elapsed_time == 0: + if _is_2d: + _active_pcam_2d.tween_started.emit() + _active_pcam_2d.reset_limit() + else: + _active_pcam_3d.tween_started.emit() + + _tween_elapsed_time = min(_tween_duration, _tween_elapsed_time + delta) + + if _is_2d: + _active_pcam_2d.is_tweening.emit() + var interpolation_destination: Vector2 = _tween_interpolate_value( + _prev_active_pcam_2d_transform.origin, + _active_pcam_2d_glob_transform.origin, + _active_pcam_2d.tween_duration, + _active_pcam_2d.tween_transition, + _active_pcam_2d.tween_ease + ) + + if _active_pcam_2d.snap_to_pixel: + camera_2d.global_position = interpolation_destination.round() + else: + camera_2d.global_position = interpolation_destination + + camera_2d.rotation = _tween_interpolate_value( + _prev_active_pcam_2d_transform.get_rotation(), + _active_pcam_2d_glob_transform.get_rotation(), + _active_pcam_2d.tween_duration, + _active_pcam_2d.tween_transition, + _active_pcam_2d.tween_ease + ) + camera_2d.zoom = _tween_interpolate_value( + _camera_zoom, + _active_pcam_2d.zoom, + _active_pcam_2d.tween_duration, + _active_pcam_2d.tween_transition, + _active_pcam_2d.tween_ease + ) + else: + _active_pcam_3d.is_tweening.emit() + camera_3d.global_position = _tween_interpolate_value( + _prev_active_pcam_3d_transform.origin, + _active_pcam_3d_glob_transform.origin, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + var prev_active_pcam_3d_quat: Quaternion = Quaternion(_prev_active_pcam_3d_transform.basis.orthonormalized()) + camera_3d.quaternion = \ + Tween.interpolate_value( + prev_active_pcam_3d_quat, \ + prev_active_pcam_3d_quat.inverse() * Quaternion(_active_pcam_3d_glob_transform.basis.orthonormalized()), + _tween_elapsed_time, \ + _active_pcam_3d.tween_duration, \ + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_attribute_changed: + if _active_pcam_3d.attributes.auto_exposure_enabled: + if _cam_auto_exposure_scale_changed: + camera_3d.attributes.auto_exposure_scale = \ + _tween_interpolate_value( + _prev_cam_auto_exposure_scale, + _active_pcam_3d.attributes.auto_exposure_scale, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_auto_exposure_speed_changed: + camera_3d.attributes.auto_exposure_speed = \ + _tween_interpolate_value( + _prev_cam_auto_exposure_scale, + _active_pcam_3d.attributes.auto_exposure_scale, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_attribute_type == 0: # CameraAttributePractical + if _active_pcam_3d.attributes.auto_exposure_enabled: + if _cam_exposure_min_sensitivity_changed: + camera_3d.attributes.auto_exposure_min_sensitivity = \ + _tween_interpolate_value( + _prev_cam_exposure_min_sensitivity, + _active_pcam_3d.attributes.auto_exposure_min_sensitivity, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_exposure_max_sensitivity_changed: + camera_3d.attributes.auto_exposure_max_sensitivity = \ + _tween_interpolate_value( + _prev_cam_exposure_max_sensitivity, + _active_pcam_3d.attributes.auto_exposure_max_sensitivity, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_dof_blur_amount_changed: + camera_3d.attributes.dof_blur_amount = \ + _tween_interpolate_value( + _prev_cam_dof_blur_amount, + _active_pcam_3d.attributes.dof_blur_amount, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_dof_blur_far_distance_changed: + camera_3d.attributes.dof_blur_far_distance = \ + _tween_interpolate_value( + _prev_cam_dof_blur_far_distance, + _active_pcam_3d.attributes.dof_blur_far_distance, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_dof_blur_far_transition_changed: + camera_3d.attributes.dof_blur_far_transition = \ + _tween_interpolate_value( + _prev_cam_dof_blur_far_transition, + _active_pcam_3d.attributes.dof_blur_far_transition, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_dof_blur_near_distance_changed: + camera_3d.attributes.dof_blur_near_distance = \ + _tween_interpolate_value( + _prev_cam_dof_blur_near_distance, + _active_pcam_3d.attributes.dof_blur_near_distance, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_dof_blur_near_transition_changed: + camera_3d.attributes.dof_blur_near_transition = \ + _tween_interpolate_value( + _prev_cam_dof_blur_near_transition, + _active_pcam_3d.attributes.dof_blur_near_transition, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + elif _cam_attribute_type == 1: # CameraAttributePhysical + if _cam_dof_blur_near_transition_changed: + camera_3d.attributes.auto_exposure_max_exposure_value = \ + _tween_interpolate_value( + _prev_cam_exposure_max_exposure_value, + _active_pcam_3d.attributes.auto_exposure_max_exposure_value, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_exposure_min_exposure_value_changed: + camera_3d.attributes.auto_exposure_min_exposure_value = \ + _tween_interpolate_value( + _prev_cam_exposure_min_exposure_value, + _active_pcam_3d.attributes.auto_exposure_min_exposure_value, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_exposure_aperture_changed: + camera_3d.attributes.exposure_aperture = \ + _tween_interpolate_value( + _prev_cam_exposure_aperture, + _active_pcam_3d.attributes.exposure_aperture, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_exposure_shutter_speed_changed: + camera_3d.attributes.exposure_shutter_speed = \ + _tween_interpolate_value( + _prev_cam_exposure_shutter_speed, + _active_pcam_3d.attributes.exposure_shutter_speed, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_frustum_far_changed: + camera_3d.attributes.frustum_far = \ + _tween_interpolate_value( + _prev_cam_frustum_far, + _active_pcam_3d.attributes.frustum_far, + _active_pcam_3d.tween_duration(), + _active_pcam_3d.tween_transition(), + _active_pcam_3d.tween_ease + ) + if _cam_frustum_near_changed: + camera_3d.attributes.frustum_near = \ + _tween_interpolate_value( + _prev_cam_frustum_far, + _active_pcam_3d.attributes.frustum_near, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_frustum_focal_length_changed: + camera_3d.attributes.frustum_focal_length = \ + _tween_interpolate_value( + _prev_cam_frustum_focal_length, + _active_pcam_3d.attributes.frustum_focal_length, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + if _cam_frustum_focus_distance_changed: + camera_3d.attributes.frustum_focus_distance = \ + _tween_interpolate_value( + _prev_cam_frustum_focus_distance, + _active_pcam_3d.attributes.frustum_focus_distance, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_h_offset_changed: + camera_3d.h_offset = \ + _tween_interpolate_value( + _prev_cam_h_offset, + _active_pcam_3d.h_offset, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_v_offset_changed: + camera_3d.v_offset = \ + _tween_interpolate_value( + _prev_cam_v_offset, + _active_pcam_3d.v_offset, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_fov_changed: + camera_3d.fov = \ + _tween_interpolate_value( + _prev_cam_fov, + _active_pcam_3d.fov, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_size_changed: + camera_3d.size = \ + _tween_interpolate_value( + _prev_cam_size, + _active_pcam_3d.size, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_frustum_offset_changed: + camera_3d.frustum_offset = \ + _tween_interpolate_value( + _prev_cam_frustum_offset, + _active_pcam_3d.frustum_offset, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_near_changed: + camera_3d.near = \ + _tween_interpolate_value( + _prev_cam_near, + _active_pcam_3d.near, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + if _cam_far_changed: + camera_3d.far = \ + _tween_interpolate_value( + _prev_cam_far, + _active_pcam_3d.far, + _active_pcam_3d.tween_duration, + _active_pcam_3d.tween_transition, + _active_pcam_3d.tween_ease + ) + + # Forcefully disables physics interpolation when tweens are instant + if _tween_is_instant: + if _is_2d: + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor >= 3: + camera_2d.set("physics_interpolation_mode", 2) + camera_2d.call("reset_physics_interpolation") + else: + if Engine.get_version_info().major == 4 and \ + Engine.get_version_info().minor >= 4: + camera_3d.set("physics_interpolation_mode", 2) + camera_3d.call("reset_physics_interpolation") + + if _tween_elapsed_time < _tween_duration: return + + _trigger_pcam_tween = false + _tween_elapsed_time = 0 + viewfinder_update.emit(true) + + if _is_2d: + _active_pcam_2d.update_limit_all_sides() + _active_pcam_2d.tween_completed.emit() + _active_pcam_2d.set_tween_skip(self, false) + if Engine.is_editor_hint(): + _active_pcam_2d.queue_redraw() + else: + if _active_pcam_3d.camera_3d_resource and _active_pcam_3d.attributes != null: + if _cam_attribute_type == 0: + if not _active_pcam_3d.attributes.dof_blur_far_enabled: + camera_3d.attributes.dof_blur_far_enabled = false + if not _active_pcam_3d.attributes.dof_blur_near_enabled: + camera_3d.attributes.dof_blur_near_enabled = false + _cam_h_offset_changed = false + _cam_v_offset_changed = false + _cam_fov_changed = false + _cam_size_changed = false + _cam_frustum_offset_changed = false + _cam_near_changed = false + _cam_far_changed = false + _cam_attribute_changed = false + + _active_pcam_3d.set_tween_skip(self, false) + _active_pcam_3d.tween_completed.emit() + + +func _tween_interpolate_value(from: Variant, to: Variant, duration: float, transition_type: int, ease_type: int) -> Variant: + return Tween.interpolate_value( + from, \ + to - from, + _tween_elapsed_time, \ + duration, \ + transition_type, + ease_type, + ) + + +func _show_viewfinder_in_play() -> void: + # Don't show the viewfinder in the actual editor or project builds + if Engine.is_editor_hint() or !OS.has_feature("editor"): return + + # Default the viewfinder node to be hidden + if is_instance_valid(_viewfinder_node): + _viewfinder_node.visible = false + + if _is_2d: + if not _active_pcam_2d.show_viewfinder_in_play: return + if _active_pcam_2d.follow_mode != _active_pcam_2d.FollowMode.FRAMED: return + else: + if not _active_pcam_3d.show_viewfinder_in_play: return + if _active_pcam_3d.follow_mode != _active_pcam_2d.FollowMode.FRAMED: return + + var canvas_layer: CanvasLayer = CanvasLayer.new() + get_tree().get_root().add_child(canvas_layer) + + # Instantiate the viewfinder scene if it isn't already + if not is_instance_valid(_viewfinder_node): + var _viewfinder_scene := load("res://addons/phantom_camera/panel/viewfinder/viewfinder_panel.tscn") + _viewfinder_node = _viewfinder_scene.instantiate() + canvas_layer.add_child(_viewfinder_node) + + _viewfinder_node.visible = true + _viewfinder_node.update_dead_zone() + + +func _update_limit_2d(side: int, limit: int) -> void: + if is_instance_valid(camera_2d): + camera_2d.set_limit(side, limit) + +func _draw_limit_2d(enabled: bool) -> void: + camera_2d.set_limit_drawing_enabled(enabled) + + +## Called when a [param PhantomCamera] is added to the scene.[br] +## [b]Note:[/b] This can only be called internally from a [param PhantomCamera] node. +func _pcam_added_to_scene(pcam: Node) -> void: + if not pcam.is_node_ready(): await pcam.ready + _check_pcam_priority(pcam) + + +## Called when a [param PhantomCamera] is removed from the scene.[br] +## [b]Note:[/b] This can only be called internally from a +## [param PhantomCamera] node. +func _pcam_removed_from_scene(pcam: Node) -> void: + if _is_2d: + if pcam == _active_pcam_2d: + _active_pcam_2d = null + _active_pcam_missing = true + _active_pcam_priority = -1 + _find_pcam_with_highest_priority() + else: + if pcam == _active_pcam_3d: + _active_pcam_3d = null + _active_pcam_missing = true + _active_pcam_priority = -1 + _find_pcam_with_highest_priority() + + +func _pcam_visibility_changed(pcam: Node) -> void: + if pcam == _active_pcam_2d or pcam == _active_pcam_3d: + _active_pcam_priority = -1 + _find_pcam_with_highest_priority() + return + _check_pcam_priority(pcam) + + +func _pcam_teleported(pcam: Node) -> void: + if _is_2d: + if not pcam == _active_pcam_2d: return + if not is_instance_valid(camera_2d): return + camera_2d.global_position = _active_pcam_2d.get_transform_output().origin + camera_2d.call("reset_physics_interpolation") +# camera_2d.reset_physics_interpolation() # TODO - For when Godot 4.3 becomes the minimum version + else: + if not pcam == _active_pcam_3d: return + if not is_instance_valid(camera_3d): return + camera_3d.global_position = _active_pcam_3d.get_transform_output().origin + camera_3d.call("reset_physics_interpolation") +# camera_3d.reset_physics_interpolation() # TODO - For when Godot 4.3 becomes the minimum version + + +func _set_layer(current_layers: int, layer_number: int, value: bool) -> int: + var mask: int = current_layers + + # From https://github.com/godotengine/godot/blob/51991e20143a39e9ef0107163eaf283ca0a761ea/scene/3d/camera_3d.cpp#L638 + if layer_number < 1 or layer_number > 20: + printerr("Render layer must be between 1 and 20.") + else: + if value: + mask |= 1 << (layer_number - 1) + else: + mask &= ~(1 << (layer_number - 1)) + + return mask + +#endregion + +#region Public Functions + +## Triggers a recalculation to determine which PhantomCamera has the highest priority. +func pcam_priority_updated(pcam: Node) -> void: + if not is_instance_valid(pcam): return + if not _pcam_is_in_host_layer(pcam): return + + if pcam == _active_pcam_2d or pcam == _active_pcam_3d: + if not pcam.visible: + refresh_pcam_list_priorty() + + if Engine.is_editor_hint(): + if _is_2d: + if not is_instance_valid(_active_pcam_2d): return + if _active_pcam_2d.priority_override: return + else: + if not is_instance_valid(_active_pcam_3d): return + if _active_pcam_3d.priority_override: return + + var current_pcam_priority: int = pcam.priority + + if current_pcam_priority >= _active_pcam_priority: + if _is_2d: + if pcam != _active_pcam_2d: + _assign_new_active_pcam(pcam) + else: + if pcam != _active_pcam_3d: + _assign_new_active_pcam(pcam) + pcam.set_tween_skip(self, false) + _active_pcam_missing = false + + if pcam == _active_pcam_2d or pcam == _active_pcam_3d: + if current_pcam_priority <= _active_pcam_priority: + _active_pcam_priority = current_pcam_priority + _find_pcam_with_highest_priority() + else: + _active_pcam_priority = current_pcam_priority + + +## Updates the viewfinder when a [param PhantomCamera] has its +## [param priority_ovrride] enabled.[br] +## [b]Note:[/b] This only affects the editor. +func _pcam_priority_override(pcam: Node, should_override: bool) -> void: + if not Engine.is_editor_hint(): return + if not _pcam_is_in_host_layer(pcam): return + if should_override: + if _is_2d: + if is_instance_valid(_active_pcam_2d): + if _active_pcam_2d.priority_override: + _active_pcam_2d.priority_override = false + else: + if is_instance_valid(_active_pcam_3d): + if _active_pcam_3d.priority_override: + _active_pcam_3d.priority_override = false + _assign_new_active_pcam(pcam) + else: + _find_pcam_with_highest_priority() + + viewfinder_update.emit(false) + + +## Updates the viewfinder when a [param PhantomCamera] has its +## [param priority_ovrride] disabled.[br] +## [b]Note:[/b] This only affects the editor. +func pcam_priority_override_disabled() -> void: + viewfinder_update.emit(false) + + +## Returns the currently active [param PhantomCamera] +func get_active_pcam() -> Node: + if _is_2d: + return _active_pcam_2d + else: + return _active_pcam_3d + + +## Returns whether if a [param PhantomCamera] should tween when it becomes +## active. If it's already active, the value will always be false. +## [b]Note:[/b] This can only be called internally from a +## [param PhantomCamera] node. +func get_trigger_pcam_tween() -> bool: + return _trigger_pcam_tween + + +## Refreshes the [param PhantomCamera] list and checks for the highest priority. [br] +## [b]Note:[/b] This should [b]not[/b] be necessary to call manually. +func refresh_pcam_list_priorty() -> void: + _active_pcam_priority = -1 + _find_pcam_with_highest_priority() + +#endregion + +#region Setters / Getters + +#func set_interpolation_mode(value: int) -> void: + #interpolation_mode = value +#func get_interpolation_mode() -> int: + #return interpolation_mode + +## Sets the [member host_layers] value. +func set_host_layers(value: int) -> void: + host_layers = value + + if not _is_child_of_camera: return + + if not _active_pcam_missing: + if _is_2d: + _pcam_host_layer_changed(_active_pcam_2d) + else: + _pcam_host_layer_changed(_active_pcam_3d) + else: + _find_pcam_with_highest_priority() + +## Enables or disables a given layer of [member host_layers]. +func set_host_layers_value(layer: int, value: bool) -> void: + host_layers = _set_layer(host_layers, layer, value) + +## Returns the [member host_layers] value. +func get_host_layers() -> int: + return host_layers + +#endregion diff --git a/godot/addons/phantom_camera/scripts/resources/Camera3DResource.cs b/godot/addons/phantom_camera/scripts/resources/Camera3DResource.cs new file mode 100644 index 0000000..7bd00b5 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/Camera3DResource.cs @@ -0,0 +1,117 @@ +using Godot; + +namespace PhantomCamera; + +public enum KeepAspect +{ + KeepWidth, + KeepHeight +} + +public enum ProjectionType +{ + Perspective, + Orthogonal, + Frustum +} + +public class Camera3DResource(Resource resource) +{ + public readonly Resource Resource = resource; + + public KeepAspect KeepAspect + { + get => (KeepAspect)(int)Resource.Call(MethodName.GetKeepAspect); + set => Resource.Call(MethodName.SetKeepAspect, (int)value); + } + + public int CullMask + { + get => (int)Resource.Call(MethodName.GetCullMask); + set => Resource.Call(MethodName.SetCullMask, value); + } + + public void SetCullMaskValue(int layer, bool value) => Resource.Call(MethodName.SetCullMaskValue, layer, value); + + public float HOffset + { + get => (float)Resource.Call(MethodName.GetHOffset); + set => Resource.Call(MethodName.SetHOffset, value); + } + + public float VOffset + { + get => (float)Resource.Call(MethodName.GetVOffset); + set => Resource.Call(MethodName.SetVOffset, value); + } + + public ProjectionType Projection + { + get => (ProjectionType)(int)Resource.Call(MethodName.GetProjection); + set => Resource.Call(MethodName.SetProjection, (int)value); + } + + public float Fov + { + get => (float)Resource.Call(MethodName.GetFov); + set => Resource.Call(MethodName.SetFov, Mathf.Clamp(value, 1, 179)); + } + + public float Size + { + get => (float)Resource.Call(MethodName.GetSize); + set => Resource.Call(MethodName.SetSize, Mathf.Clamp(value, 0.001f, float.PositiveInfinity)); + } + + public Vector2 FrustumOffset + { + get => (Vector2)Resource.Call(MethodName.GetFrustumOffset); + set => Resource.Call(MethodName.SetFrustumOffset, value); + } + + public float Near + { + get => (float)Resource.Call(MethodName.GetNear); + set => Resource.Call(MethodName.SetNear, Mathf.Clamp(value, 0.001f, float.PositiveInfinity)); + } + + public float Far + { + get => (float)Resource.Call(MethodName.GetFar); + set => Resource.Call(MethodName.SetFar, Mathf.Clamp(value, 0.01f, float.PositiveInfinity)); + } + + public static class MethodName + { + public const string GetKeepAspect = "get_keep_aspect"; + public const string SetKeepAspect = "set_keep_aspect"; + + public const string GetCullMask = "get_cull_mask"; + public const string SetCullMask = "set_cull_mask"; + public const string SetCullMaskValue = "set_cull_mask_value"; + + public const string GetHOffset = "get_h_offset"; + public const string SetHOffset = "set_h_offset"; + + public const string GetVOffset = "get_v_offset"; + public const string SetVOffset = "set_v_offset"; + + public const string GetProjection = "get_projection"; + public const string SetProjection = "set_projection"; + + public const string GetFov = "get_fov"; + public const string SetFov = "set_fov"; + + public const string GetSize = "get_size"; + public const string SetSize = "set_size"; + + public const string GetFrustumOffset = "get_frustum_offset"; + public const string SetFrustumOffset = "set_frustum_offset"; + + public const string GetNear = "get_near"; + public const string SetNear = "set_near"; + + public const string GetFar = "get_far"; + public const string SetFar = "set_far"; + } +} diff --git a/godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise2D.cs b/godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise2D.cs new file mode 100644 index 0000000..16b7273 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise2D.cs @@ -0,0 +1,92 @@ +using Godot; + +namespace PhantomCamera.Noise; + +public class PhantomCameraNoise2D(Resource resource) +{ + public readonly Resource Resource = resource; + + public float Amplitude + { + get => (float)Resource.Call(MethodName.GetAmplitude); + set => Resource.Call(MethodName.SetAmplitude, value); + } + + public float Frequency + { + get => (float)Resource.Call(MethodName.GetFrequency); + set => Resource.Call(MethodName.SetFrequency, value); + } + + public bool RandomizeNoiseSeed + { + get => (bool)Resource.Call(MethodName.GetRandomizeNoiseSeed); + set => Resource.Call(MethodName.SetRandomizeNoiseSeed, value); + } + + public int NoiseSeed + { + get => (int)Resource.Call(MethodName.GetNoiseSeed); + set => Resource.Call(MethodName.SetNoiseSeed, value); + } + + public bool RotationalNoise + { + get => (bool)Resource.Call(MethodName.GetRotationalNoise); + set => Resource.Call(MethodName.SetRotationalNoise, value); + } + + public bool PositionalNoise + { + get => (bool)Resource.Call(MethodName.GetPositionalNoise); + set => Resource.Call(MethodName.SetPositionalNoise, value); + } + + public float RotationalMultiplier + { + get => (float)Resource.Call(MethodName.GetRotationalMultiplier); + set => Resource.Call(MethodName.SetRotationalMultiplier, value); + } + + public float PositionalMultiplierX + { + get => (float)Resource.Call(MethodName.GetPositionalMultiplierX); + set => Resource.Call(MethodName.SetPositionalMultiplierX, value); + } + + public float PositionalMultiplierY + { + get => (float)Resource.Call(MethodName.GetPositionalMultiplierY); + set => Resource.Call(MethodName.SetPositionalMultiplierY, value); + } + + public static class MethodName + { + public const string GetAmplitude = "get_amplitude"; + public const string SetAmplitude = "set_amplitude"; + + public const string GetFrequency = "get_frequency"; + public const string SetFrequency = "set_frequency"; + + public const string GetRandomizeNoiseSeed = "get_randomize_noise_seed"; + public const string SetRandomizeNoiseSeed = "set_randomize_noise_seed"; + + public const string GetNoiseSeed = "get_noise_seed"; + public const string SetNoiseSeed = "set_noise_seed"; + + public const string GetRotationalNoise = "get_rotational_noise"; + public const string SetRotationalNoise = "set_rotational_noise"; + + public const string GetPositionalNoise = "get_positional_noise"; + public const string SetPositionalNoise = "set_positional_noise"; + + public const string GetRotationalMultiplier = "get_rotational_multiplier"; + public const string SetRotationalMultiplier = "set_rotational_multiplier"; + + public const string GetPositionalMultiplierX = "get_positional_multiplier_x"; + public const string SetPositionalMultiplierX = "set_positional_multiplier_x"; + + public const string GetPositionalMultiplierY = "get_positional_multiplier_y"; + public const string SetPositionalMultiplierY = "set_positional_multiplier_y"; + } +} diff --git a/godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise3D.cs b/godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise3D.cs new file mode 100644 index 0000000..175a427 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/PhantomCameraNoise3D.cs @@ -0,0 +1,119 @@ +using Godot; + +namespace PhantomCamera.Noise; + +public class PhantomCameraNoise3D(Resource resource) +{ + public readonly Resource Resource = resource; + + public float Amplitude + { + get => (float)Resource.Call(MethodName.GetAmplitude); + set => Resource.Call(MethodName.SetAmplitude, value); + } + + public float Frequency + { + get => (float)Resource.Call(MethodName.GetFrequency); + set => Resource.Call(MethodName.SetFrequency, value); + } + + public bool RandomizeNoiseSeed + { + get => (bool)Resource.Call(MethodName.GetRandomizeNoiseSeed); + set => Resource.Call(MethodName.SetRandomizeNoiseSeed, value); + } + + public int NoiseSeed + { + get => (int)Resource.Call(MethodName.GetNoiseSeed); + set => Resource.Call(MethodName.SetNoiseSeed, value); + } + + public bool RotationalNoise + { + get => (bool)Resource.Call(MethodName.GetRotationalNoise); + set => Resource.Call(MethodName.SetRotationalNoise, value); + } + + public bool PositionalNoise + { + get => (bool)Resource.Call(MethodName.GetPositionalNoise); + set => Resource.Call(MethodName.SetPositionalNoise, value); + } + + public float RotationalMultiplierX + { + get => (float)Resource.Call(MethodName.GetRotationalMultiplierX); + set => Resource.Call(MethodName.SetRotationalMultiplierX, value); + } + + public float RotationalMultiplierY + { + get => (float)Resource.Call(MethodName.GetRotationalMultiplierY); + set => Resource.Call(MethodName.SetRotationalMultiplierY, value); + } + + public float RotationalMultiplierZ + { + get => (float)Resource.Call(MethodName.GetRotationalMultiplierZ); + set => Resource.Call(MethodName.SetRotationalMultiplierZ, value); + } + + public float PositionalMultiplierX + { + get => (float)Resource.Call(MethodName.GetPositionalMultiplierX); + set => Resource.Call(MethodName.SetPositionalMultiplierX, value); + } + + public float PositionalMultiplierY + { + get => (float)Resource.Call(MethodName.GetPositionalMultiplierY); + set => Resource.Call(MethodName.SetPositionalMultiplierY, value); + } + + public float PositionalMultiplierZ + { + get => (float)Resource.Call(MethodName.GetPositionalMultiplierZ); + set => Resource.Call(MethodName.SetPositionalMultiplierZ, value); + } + + public static class MethodName + { + public const string GetAmplitude = "get_amplitude"; + public const string SetAmplitude = "set_amplitude"; + + public const string GetFrequency = "get_frequency"; + public const string SetFrequency = "set_frequency"; + + public const string GetRandomizeNoiseSeed = "get_randomize_noise_seed"; + public const string SetRandomizeNoiseSeed = "set_randomize_noise_seed"; + + public const string GetNoiseSeed = "get_noise_seed"; + public const string SetNoiseSeed = "set_noise_seed"; + + public const string GetRotationalNoise = "get_rotational_noise"; + public const string SetRotationalNoise = "set_rotational_noise"; + + public const string GetPositionalNoise = "get_positional_noise"; + public const string SetPositionalNoise = "set_positional_noise"; + + public const string GetRotationalMultiplierX = "get_rotational_multiplier_x"; + public const string SetRotationalMultiplierX = "set_rotational_multiplier_x"; + + public const string GetRotationalMultiplierY = "get_rotational_multiplier_y"; + public const string SetRotationalMultiplierY = "set_rotational_multiplier_y"; + + public const string GetRotationalMultiplierZ = "get_rotational_multiplier_z"; + public const string SetRotationalMultiplierZ = "set_rotational_multiplier_z"; + + public const string GetPositionalMultiplierX = "get_positional_multiplier_x"; + public const string SetPositionalMultiplierX = "set_positional_multiplier_x"; + + public const string GetPositionalMultiplierY = "get_positional_multiplier_y"; + public const string SetPositionalMultiplierY = "set_positional_multiplier_y"; + + public const string GetPositionalMultiplierZ = "get_positional_multiplier_z"; + public const string SetPositionalMultiplierZ = "set_positional_multiplier_z"; + } +} diff --git a/godot/addons/phantom_camera/scripts/resources/PhantomCameraTween.cs b/godot/addons/phantom_camera/scripts/resources/PhantomCameraTween.cs new file mode 100644 index 0000000..1c332b7 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/PhantomCameraTween.cs @@ -0,0 +1,64 @@ +using Godot; + +namespace PhantomCamera; + +public enum TransitionType +{ + Linear, + Sine, + Quint, + Quart, + Quad, + Expo, + Elastic, + Cubic, + Circ, + Bounce, + Back +} + +public enum EaseType +{ + EaseIn, + EaseOut, + EaseInOut, + EaseOutIn +} + +public static class PhantomCameraTweenExtensions +{ + public static PhantomCameraTween AsPhantomCameraTween(this Resource resource) + { + return new PhantomCameraTween(resource); + } +} + +public class PhantomCameraTween(Resource tweenResource) +{ + public Resource Resource { get; } = tweenResource; + + public float Duration + { + get => (float)Resource.Get(PropertyName.Duration); + set => Resource.Set(PropertyName.Duration, value); + } + + public TransitionType Transition + { + get => (TransitionType)(int)Resource.Get(PropertyName.Transition); + set => Resource.Set(PropertyName.Transition, (int)value); + } + + public EaseType Ease + { + get => (EaseType)(int)Resource.Get(PropertyName.Ease); + set => Resource.Set(PropertyName.Ease, (int)value); + } + + public static class PropertyName + { + public const string Duration = "duration"; + public const string Transition = "transition"; + public const string Ease = "ease"; + } +} diff --git a/godot/addons/phantom_camera/scripts/resources/camera_3d_resource.gd b/godot/addons/phantom_camera/scripts/resources/camera_3d_resource.gd new file mode 100644 index 0000000..c630e16 --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/camera_3d_resource.gd @@ -0,0 +1,110 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_camera_3d_resource.svg") +class_name Camera3DResource +extends Resource + +## Resource for [PhantomCamera3D] to override various [Camera3D] properties. +## +## The overrides defined here will be applied to the [Camera3D] upon the +## [PhantomCamera3D] becoming active. + +enum KeepAspect { + KEEP_WIDTH = 0, ## Preserves the horizontal aspect ratio; also known as Vert- scaling. This is usually the best option for projects running in portrait mode, as taller aspect ratios will benefit from a wider vertical FOV. + KEEP_HEIGHT = 1, ## Preserves the vertical aspect ratio; also known as Hor+ scaling. This is usually the best option for projects running in landscape mode, as wider aspect ratios will automatically benefit from a wider horizontal FOV. +} + +enum ProjectionType { + PERSPECTIVE = 0, ## Perspective projection. Objects on the screen becomes smaller when they are far away. + ORTHOGONAL = 1, ## Orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are. + FRUSTUM = 2, ## Frustum projection. This mode allows adjusting frustum_offset to create "tilted frustum" effects. +} + +## Overrides [member Camera3D.keep_aspect]. +@export var keep_aspect: KeepAspect = KeepAspect.KEEP_HEIGHT: + set(value): + keep_aspect = value + emit_changed() + get: + return keep_aspect + +## Overrides [member Camera3D.cull_mask]. +@export_flags_3d_render var cull_mask: int = 1048575: + set(value): + cull_mask = value + emit_changed() + get: + return cull_mask + +## Overrides [member Camera3D.h_offset]. +@export_range(0, 1, 0.001, "or_greater", "or_less", "hide_slider", "suffix:m") var h_offset: float = 0: + set(value): + h_offset = value + emit_changed() + get: + return h_offset + +## Overrides [member Camera3D.v_offset]. +@export_range(0, 1, 0.001, "or_greater", "or_less", "hide_slider", "suffix:m") var v_offset: float = 0: + set(value): + v_offset = value + emit_changed() + +## Overrides [member Camera3D.projection]. +@export var projection: ProjectionType = ProjectionType.PERSPECTIVE: + set(value): + projection = value + notify_property_list_changed() + emit_changed() + get: + return projection + +## Overrides [member Camera3D.fov]. +@export_range(1, 179, 0.1, "degrees") var fov: float = 75: + set(value): + fov = value + emit_changed() + get: + return fov + +## Overrides [member Camera3D.size]. +@export_range(0.001, 100, 0.001, "suffix:m", "or_greater") var size: float = 1: + set(value): + size = value + emit_changed() + get: + return size + +## Overrides [member Camera3d.frustum_offset]. +@export var frustum_offset: Vector2 = Vector2.ZERO: + set(value): + frustum_offset = value + emit_changed() + get: + return frustum_offset + +## Overrides [member Camera3D.near]. +@export_range(0.001, 10, 0.001, "suffix:m", "or_greater") var near: float = 0.05: + set(value): + near = value + emit_changed() + get: + return near + +## Overrides [member Camera3D.far]. +@export_range(0.01, 4000, 0.001, "suffix:m","or_greater") var far: float = 4000: + set(value): + far = value + emit_changed() + get: + return far + + +func _validate_property(property: Dictionary) -> void: + if property.name == "fov" and not projection == ProjectionType.PERSPECTIVE: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "size" and projection == ProjectionType.PERSPECTIVE: + property.usage = PROPERTY_USAGE_NO_EDITOR + + if property.name == "frustum_offset" and not projection == ProjectionType.FRUSTUM: + property.usage = PROPERTY_USAGE_NO_EDITOR diff --git a/godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_2d.gd b/godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_2d.gd new file mode 100644 index 0000000..cc87dba --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_2d.gd @@ -0,0 +1,228 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_noise_resource.svg") +class_name PhantomCameraNoise2D +extends Resource + +## A resource type used to apply noise, or shake, to [Camera2D]s that have a [PhantomCameraHost] as a child. +## +## Is a resource type that defines, calculates and outputs the noise values to a [Camera2D] through active +## [PhantomCamera3D].[br] +## It can be applied to either [PhantomCameraNoiseEmitter2D] or a [PhantomCamera2D] noise property directly + +#region Exported Properties + +## Defines the size of the noise pattern.[br] +## Higher values will increase the range the noise can reach. +@export_range(0, 1000, 0.001, "or_greater") var amplitude: float = 10: + set = set_amplitude, + get = get_amplitude + +## Sets the density of the noise pattern.[br] +## Higher values will result in more erratic noise. +@export_range(0, 10, 0.001, "or_greater") var frequency: float = 0.5: + set = set_frequency, + get = get_frequency + +## If true, randomizes the noise pattern every time the noise is run.[br] +## If disabled, [member seed] can be used to define a fixed noise pattern. +@export var randomize_noise_seed: bool = true: + set = set_randomize_noise_seed, + get = get_randomize_noise_seed + +## Sets a predetermined seed noise value.[br] +## Useful if wanting to achieve a persistent noise pattern every time the noise is emitted. +@export var noise_seed: int = 0: + set = set_noise_seed, + get = get_noise_seed + +## Enables noise changes to the [member Camera2D.offset] position. +@export var positional_noise: bool = true: + set = set_positional_noise, + get = get_positional_noise + +## Enables noise changes to the [Camera2D]'s rotation. +@export var rotational_noise: bool = false: + set = set_rotational_noise, + get = get_rotational_noise + +@export_group("Positional Multiplier") +## Multiplies positional noise amount in the X-axis.[br] +## Set the value to [param 0] to disable noise in the axis. +@export_range(0, 1, 0.001, "or_greater") var positional_multiplier_x: float = 1: + set = set_positional_multiplier_x, + get = get_positional_multiplier_x + +## Multiplies positional noise amount in the Y-axis.[br] +## Set the value to [param 0] to disable noise in the axis. +@export_range(0, 1, 0.001, "or_greater") var positional_multiplier_y: float = 1: + set = set_positional_multiplier_y, + get = get_positional_multiplier_y + +@export_group("Rotational Multiplier") +## Multiplies rotational noise amount. +@export_range(0, 1, 0.001, "or_greater") var rotational_multiplier: float = 1: + set = set_rotational_multiplier, + get = get_rotational_multiplier + +#endregion + +#region Private Variables + +var _noise_algorithm: FastNoiseLite = FastNoiseLite.new() + +var _noise_positional_multiplier: Vector2 = Vector2( + positional_multiplier_x, + positional_multiplier_y +) + +var _trauma: float = 0.0: + set(value): + _trauma = value + +var _noise_time: float = 0.0 + +#endregion + +#region Private Functions + +func _init(): + _noise_algorithm.noise_type = FastNoiseLite.TYPE_PERLIN + if randomize_noise_seed: _noise_algorithm.seed = randi() + _noise_algorithm.frequency = frequency + + +func _validate_property(property: Dictionary) -> void: + if randomize_noise_seed and property.name == "noise_seed": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if not rotational_noise and property.name == "rotational_multiplier": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if not positional_noise: + match property.name: + "positional_multiplier_x", \ + "positional_multiplier_y": + property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _get_noise_from_seed(noise_seed: int) -> float: + return _noise_algorithm.get_noise_2d(noise_seed, _noise_time) * amplitude + + +func set_trauma(value: float) -> void: + _trauma = value + +#endregion + +#region Public Functions + +func get_noise_transform(delta: float) -> Transform2D: + var output_position: Vector2 = Vector2.ZERO + var output_rotation: float = 0.0 + _noise_time += delta + _trauma = maxf(_trauma, 0.0) + + if positional_noise: + for i in 2: + output_position[i] = _noise_positional_multiplier[i] * pow(_trauma, 2) * _get_noise_from_seed(i + noise_seed) + if rotational_noise: + output_rotation = rotational_multiplier / 100 * pow(_trauma, 2) * _get_noise_from_seed(noise_seed) + + return Transform2D(output_rotation, output_position) + + +func reset_noise_time() -> void: + _noise_time = 0 + +#endregion + +#region Setters & Getters + +## Sets the [member amplitude] value. +func set_amplitude(value: float) -> void: + amplitude =value + +## Returns the [member amplitude] value. +func get_amplitude() -> float: + return amplitude + + +## Sets the [member frequency] value. +func set_frequency(value: float) -> void: + frequency = value + _noise_algorithm.frequency = value + +## Returns the [member frequency] value. +func get_frequency() -> float: + return frequency + + +## Sets the [member randomize_seed] value. +func set_randomize_noise_seed(value: int) -> void: + randomize_noise_seed = value + if value: _noise_algorithm.seed = randi() + notify_property_list_changed() + +## Returns the [member randomize_seed] value. +func get_randomize_noise_seed() -> int: + return randomize_noise_seed + + +## Sets the [member randomize_seed] value. +func set_noise_seed(value: int) -> void: + noise_seed = value + +## Returns the [member seed] value. +func get_noise_seed() -> int: + return noise_seed + + +## Sets the [member positional_noise] value. +func set_positional_noise(value: bool) -> void: + positional_noise = value + notify_property_list_changed() + +## Returns the [member positional_noise] value. +func get_positional_noise() -> bool: + return positional_noise + + +## Sets the [member rotational_noise] value. +func set_rotational_noise(value: bool) -> void: + rotational_noise = value + notify_property_list_changed() + +## Returns the [member rotational_noise] value. +func get_rotational_noise() -> bool: + return rotational_noise + + +## Sets the [member positional_multiplier_x] value. +func set_positional_multiplier_x(value: float) -> void: + positional_multiplier_x = value + _noise_positional_multiplier.x = value + +## Returns the [member positional_multiplier_x] value. +func get_positional_multiplier_x() -> float: + return positional_multiplier_x + + +## Sets the [member positional_multiplier_y] value. +func set_positional_multiplier_y(value: float) -> void: + positional_multiplier_y = value + _noise_positional_multiplier.y = value + +## Returns the [member positional_multiplier_y] value. +func get_positional_multiplier_y() -> float: + return positional_multiplier_y + + +## Sets the [member rotational_multiplier] value. +func set_rotational_multiplier(value: float) -> void: + rotational_multiplier = value + +## Returns the [member rotational_multiplier] value. +func get_rotational_multiplier() -> float: + return rotational_multiplier + +#endregion diff --git a/godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_3d.gd b/godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_3d.gd new file mode 100644 index 0000000..6cf840f --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/phantom_camera_noise_3d.gd @@ -0,0 +1,301 @@ +@tool +@icon("res://addons/phantom_camera/icons/phantom_camera_noise_resource.svg") +class_name PhantomCameraNoise3D +extends Resource + +## A resource type used to apply noise, or shake, to [Camera3D]s that have a [PhantomCameraHost] as a child. +## +## Is a resource type that defines, calculates and outputs the noise values to a [Camera3D] through active +## [PhantomCamera3D].[br] +## It can be applied to either [PhantomCameraNoiseEmitter3D] or a [PhantomCamera3D] noise property directly + +#region Exported Properties + +## Defines the size of the noise pattern.[br] +## Higher values will increase the range the noise can reach. +@export_range(0, 100, 0.001, "or_greater") var amplitude: float = 10: + set = set_amplitude, + get = get_amplitude + +## Sets the density of the noise pattern.[br] +## Higher values will result in more erratic noise. +@export_range(0, 10, 0.001, "or_greater") var frequency: float = 0.2: + set = set_frequency, + get = get_frequency + +## If true, randomizes the noise pattern every time the noise is run.[br] +## If disabled, [member seed] can be used to define a fixed noise pattern. +@export var randomize_noise_seed: bool = true: + set = set_randomize_noise_seed, + get = get_randomize_noise_seed + +## Sets a predetermined seed noise value.[br] +## Useful if wanting to achieve a persistent noise pattern every time the noise is emitted. +@export var noise_seed: int = 0: + set = set_noise_seed, + get = get_noise_seed + +## Enables noise changes to the [Camera3D]'s rotation. +@export var rotational_noise: bool = true: + set = set_rotational_noise, + get = get_rotational_noise + +## Enables noise changes to the camera's position.[br][br] +## [b]Important[/b][br]This can cause geometry clipping if the camera gets too close while this is active. +@export var positional_noise: bool = false: + set = set_positional_noise, + get = get_positional_noise + +@export_group("Rotational Multiplier") +## Multiplies rotational noise amount in the X-axis.[br] +## Set the value to [param 0] to disable noise in the axis. +@export_range(0, 1, 0.001, "or_greater") var rotational_multiplier_x: float = 1: + set = set_rotational_multiplier_x, + get = get_rotational_multiplier_x + +## Multiplies rotational noise amount in the Y-axis.[br] +## Set the value to [param 0] to disable noise in the axis. +@export_range(0, 1, 0.001, "or_greater") var rotational_multiplier_y: float = 1: + set = set_rotational_multiplier_y, + get = get_rotational_multiplier_y + +## Multiplies rotational noise amount in the Z-axis.[br] +## Set the value to [param 0] to disable noise in the axis. +@export_range(0, 1, 0.001, "or_greater") var rotational_multiplier_z: float = 1: + set = set_rotational_multiplier_z, + get = get_rotational_multiplier_z + +@export_group("Positional Multiplier") +## Multiplies positional noise amount in the X-axis.[br] +## Set the value to [param 0] to disable noise in the axis.[br] +## [b]Note:[/b] Rotational Offset is recommended to avoid potential camera clipping with the environment. +@export_range(0, 1, 0.001, "or_greater") var positional_multiplier_x: float = 1: + set = set_positional_multiplier_x, + get = get_positional_multiplier_x + +## Multiplies positional noise amount in the Y-axis.[br] +## Set the value to [param 0] to disable noise in the axis.[br] +## [b]Note:[/b] Rotational Offset is recommended to avoid potential camera clipping with the environment. +@export_range(0, 1, 0.001, "or_greater") var positional_multiplier_y: float = 1: + set = set_positional_multiplier_y, + get = get_positional_multiplier_y + +## Multiplies positional noise amount in the Z-axis.[br] +## Set the value to [param 0] to disable noise in the axis.[br] +## [b]Note:[/b] Rotational Offset is recommended to avoid potential camera clipping with the environment. +@export_range(0, 1, 0.001, "or_greater") var positional_multiplier_z: float = 1: + set = set_positional_multiplier_z, + get = get_positional_multiplier_z + +#endregion + +#region Private Variables + +var _noise_algorithm: FastNoiseLite = FastNoiseLite.new() + +var _noise_rotational_multiplier: Vector3 = Vector3( + rotational_multiplier_x, + rotational_multiplier_y, + rotational_multiplier_z, +) + +var _noise_positional_multiplier: Vector3 = Vector3( + positional_multiplier_x, + positional_multiplier_y, + positional_multiplier_z, +) + +var _trauma: float = 0.0: + set(value): + _trauma = value + if _trauma == 0.0: + _noise_time = 0.0 + +var _noise_time: float = 0.0 + +#endregion + +#region Private Functions + +func _init(): + _noise_algorithm.noise_type = FastNoiseLite.TYPE_PERLIN + + if randomize_noise_seed: _noise_algorithm.seed = randi() + _noise_algorithm.frequency = frequency + + +func _validate_property(property: Dictionary) -> void: + if randomize_noise_seed and property.name == "noise_seed": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if not rotational_noise: + match property.name: + "rotational_multiplier_x", \ + "rotational_multiplier_y", \ + "rotational_multiplier_z": + property.usage = PROPERTY_USAGE_NO_EDITOR + + if not positional_noise: + match property.name: + "positional_multiplier_x", \ + "positional_multiplier_y", \ + "positional_multiplier_z": + property.usage = PROPERTY_USAGE_NO_EDITOR + + +func _get_noise_from_seed(noise_seed: int) -> float: + return _noise_algorithm.get_noise_2d(noise_seed, _noise_time) * amplitude + + +func set_trauma(value: float) -> void: + _trauma = value + +#endregion + +#region Public Functions + +func get_noise_transform(delta: float) -> Transform3D: + var output_rotation: Vector3 = Vector3.ZERO + var output_position: Vector3 = Vector3.ZERO + _noise_time += delta + _trauma = maxf(_trauma, 0.0) + + for i in 3: + if rotational_noise: + output_rotation[i] = deg_to_rad( + _noise_rotational_multiplier[i] * pow(_trauma, 2) * _get_noise_from_seed(i + noise_seed) + ) + + if positional_noise: + output_position[i] += _noise_positional_multiplier[i] / 10 * \ + pow(_trauma, 2) * _get_noise_from_seed(i + noise_seed) + + return Transform3D(Quaternion.from_euler(output_rotation), output_position) + + +func reset_noise_time() -> void: + _noise_time = 0 + +#endregion + +#region Setters & Getters + +## Sets the [member amplitude] value. +func set_amplitude(value: float) -> void: + amplitude =value + +## Returns the [member amplitude] value. +func get_amplitude() -> float: + return amplitude + + +## Sets the [member frequency] value. +func set_frequency(value: float) -> void: + frequency = value + _noise_algorithm.frequency = value + +## Returns the [member frequency] value. +func get_frequency() -> float: + return frequency + + +## Sets the [member randomize_seed] value. +func set_randomize_noise_seed(value: int) -> void: + randomize_noise_seed = value + if value: _noise_algorithm.seed = randi() + notify_property_list_changed() + +## Returns the [member randomize_seed] value. +func get_randomize_noise_seed() -> int: + return randomize_noise_seed + + +## Sets the [member randomize_seed] value. +func set_noise_seed(value: int) -> void: + noise_seed = value + +## Returns the [member seed] value. +func get_noise_seed() -> int: + return noise_seed + + +## Sets the [member positional_noise] value. +func set_positional_noise(value: bool) -> void: + positional_noise = value + notify_property_list_changed() + +## Returns the [member positional_noise] value. +func get_positional_noise() -> bool: + return positional_noise + + +## Sets the [member rotational_noise] value. +func set_rotational_noise(value: bool) -> void: + rotational_noise = value + notify_property_list_changed() + +## Returns the [member rotational_noise] value. +func get_rotational_noise() -> bool: + return rotational_noise + + +## Sets the [member positional_multiplier_x] value. +func set_positional_multiplier_x(value: float) -> void: + positional_multiplier_x = value + _noise_positional_multiplier.x = value + +## Returns the [member positional_multiplier_x] value. +func get_positional_multiplier_x() -> float: + return positional_multiplier_x + + +## Sets the [member positional_multiplier_y] value. +func set_positional_multiplier_y(value: float) -> void: + positional_multiplier_y = value + _noise_positional_multiplier.y = value + +## Returns the [member positional_multiplier_y] value. +func get_positional_multiplier_y() -> float: + return positional_multiplier_y + + +## Sets the [member positional_multiplier_z] value. +func set_positional_multiplier_z(value: float) -> void: + positional_multiplier_z = value + _noise_positional_multiplier.z = value + +## Returns the [member positional_multiplier_z] value. +func get_positional_multiplier_z() -> float: + return positional_multiplier_z + + +## Sets the [member rotational_multiplier_x] value. +func set_rotational_multiplier_x(value: float) -> void: + rotational_multiplier_x = value + _noise_rotational_multiplier.x = value + +## Returns the [member rotational_multiplier_x] value. +func get_rotational_multiplier_x() -> float: + return rotational_multiplier_x + + +## Sets the [member rotational_multiplier_y] value. +func set_rotational_multiplier_y(value: float) -> void: + rotational_multiplier_y = value + _noise_rotational_multiplier.y = value + +## Returns the [member rotational_multiplier_y] value. +func get_rotational_multiplier_y() -> float: + return rotational_multiplier_y + + +## Sets the [member rotational_multiplier_z] value. +func set_rotational_multiplier_z(value: float) -> void: + rotational_multiplier_z = value + _noise_rotational_multiplier.z = value + +## Returns the [member rotational_multiplier_z] value. +func get_rotational_multiplier_z() -> float: + return rotational_multiplier_z + + #endregion diff --git a/godot/addons/phantom_camera/scripts/resources/tween_resource.gd b/godot/addons/phantom_camera/scripts/resources/tween_resource.gd new file mode 100644 index 0000000..0a3b46f --- /dev/null +++ b/godot/addons/phantom_camera/scripts/resources/tween_resource.gd @@ -0,0 +1,41 @@ +@icon("res://addons/phantom_camera/icons/phantom_camera_tween.svg") +class_name PhantomCameraTween +extends Resource + +## Tweening resource for [PhantomCamera2D] and [PhantomCamera3D]. +## +## Defines how [param PhantomCameras] transition between one another. +## Changing the tween values for a given [param PhantomCamera] determines how +## transitioning to that instance will look like. + +enum TransitionType { + LINEAR = 0, ## The animation is interpolated linearly. + SINE = 1, ## The animation is interpolated using a sine function. + QUINT = 2, ## The animation is interpolated with a quintic (to the power of 5) function. + QUART = 3, ## The animation is interpolated with a quartic (to the power of 4) function. + QUAD = 4, ## The animation is interpolated with a quadratic (to the power of 2) function. + EXPO = 5, ## The animation is interpolated with an exponential (to the power of x) function. + ELASTIC = 6, ## The animation is interpolated with elasticity, wiggling around the edges. + CUBIC = 7, ## The animation is interpolated with a cubic (to the power of 3) function. + CIRC = 8, ## The animation is interpolated with a function using square roots. + BOUNCE = 9, ## The animation is interpolated by bouncing at the end. + BACK = 10, ## The animation is interpolated backing out at ends. +# CUSTOM = 11, +# NONE = 12, +} + +enum EaseType { + EASE_IN = 0, ## The interpolation starts slowly and speeds up towards the end. + EASE_OUT = 1, ## The interpolation starts quickly and slows down towards the end. + EASE_IN_OUT = 2, ## A combination of EASE_IN and EASE_OUT. The interpolation is slowest at both ends. + EASE_OUT_IN = 3, ## A combination of EASE_IN and EASE_OUT. The interpolation is fastest at both ends. +} + +## The time it takes to tween to this PhantomCamera in [param seconds]. +@export var duration: float = 1.0 + +## The transition bezier type for the tween. The options are defined in the [enum TransitionType]. +@export var transition: TransitionType = TransitionType.LINEAR + +## The ease type for the tween. The options are defined in the [enum EaseType]. +@export var ease: EaseType = EaseType.EASE_IN_OUT diff --git a/godot/addons/phantom_camera/themes/button_focus.tres b/godot/addons/phantom_camera/themes/button_focus.tres new file mode 100644 index 0000000..e6fcc45 --- /dev/null +++ b/godot/addons/phantom_camera/themes/button_focus.tres @@ -0,0 +1,17 @@ +[gd_resource type="StyleBoxFlat" format=3 uid="uid://p058hmj3uut0"] + +[resource] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 diff --git a/godot/addons/phantom_camera/themes/button_hover.tres b/godot/addons/phantom_camera/themes/button_hover.tres new file mode 100644 index 0000000..9d37a86 --- /dev/null +++ b/godot/addons/phantom_camera/themes/button_hover.tres @@ -0,0 +1,13 @@ +[gd_resource type="StyleBoxFlat" format=3 uid="uid://5weqvkjsfso3"] + +[resource] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.960784, 0.960784, 0.960784, 1) +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 diff --git a/godot/addons/phantom_camera/themes/button_normal.tres b/godot/addons/phantom_camera/themes/button_normal.tres new file mode 100644 index 0000000..4eae33d --- /dev/null +++ b/godot/addons/phantom_camera/themes/button_normal.tres @@ -0,0 +1,17 @@ +[gd_resource type="StyleBoxFlat" format=3 uid="uid://bclbwo3xrdat0"] + +[resource] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 diff --git a/godot/addons/phantom_camera/themes/theme.tres b/godot/addons/phantom_camera/themes/theme.tres new file mode 100644 index 0000000..7ce53d8 --- /dev/null +++ b/godot/addons/phantom_camera/themes/theme.tres @@ -0,0 +1,102 @@ +[gd_resource type="Theme" load_steps=12 format=3 uid="uid://bhppejri5dbsf"] + +[ext_resource type="FontFile" uid="uid://dve7mgsjik4dg" path="res://addons/phantom_camera/fonts/Nunito-Regular.ttf" id="1_5rtjh"] +[ext_resource type="StyleBox" uid="uid://5weqvkjsfso3" path="res://addons/phantom_camera/themes/button_hover.tres" id="2_du6h5"] +[ext_resource type="StyleBox" uid="uid://bclbwo3xrdat0" path="res://addons/phantom_camera/themes/button_normal.tres" id="3_a8j1f"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ek0y3"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rjkuq"] +content_margin_left = 8.0 +content_margin_top = 4.0 +content_margin_right = 8.0 +content_margin_bottom = 4.0 +bg_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_x7u0w"] +content_margin_top = 2.0 +content_margin_right = 8.0 +bg_color = Color(0.0784314, 0.109804, 0.129412, 1) +border_width_top = 2 +border_width_right = 2 +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_right = 10 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dln2q"] +content_margin_top = 8.0 +content_margin_bottom = 8.0 +draw_center = false + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_wk7ot"] +bg_color = Color(0.227451, 0.72549, 0.603922, 1) +border_color = Color(0.227451, 0.72549, 0.603922, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jidrt"] +bg_color = Color(0.960784, 0.960784, 0.960784, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_o2xwc"] +bg_color = Color(0.960784, 0.960784, 0.960784, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ul127"] +draw_center = false +border_width_left = 4 +border_width_right = 4 +border_color = Color(0.8, 0.8, 0.8, 0) + +[resource] +default_font = ExtResource("1_5rtjh") +Button/colors/font_color = Color(0.227451, 0.72549, 0.603922, 1) +Button/colors/font_focus_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/font_hover_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/font_hover_pressed_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/font_pressed_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/icon_focus_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/icon_hover_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/icon_hover_pressed_color = Color(0.227451, 0.72549, 0.603922, 1) +Button/colors/icon_normal_color = Color(0.0784314, 0.109804, 0.129412, 1) +Button/colors/icon_pressed_color = Color(0.227451, 0.72549, 0.603922, 1) +Button/styles/focus = SubResource("StyleBoxFlat_ek0y3") +Button/styles/hover = ExtResource("2_du6h5") +Button/styles/hover_pressed = null +Button/styles/normal = ExtResource("3_a8j1f") +Button/styles/pressed = SubResource("StyleBoxFlat_rjkuq") +PanelContainer/styles/panel = SubResource("StyleBoxFlat_x7u0w") +ScrollContainer/styles/panel = SubResource("StyleBoxFlat_dln2q") +VBoxContainer/constants/separation = 8 +VScrollBar/styles/grabber = SubResource("StyleBoxFlat_wk7ot") +VScrollBar/styles/grabber_highlight = SubResource("StyleBoxFlat_jidrt") +VScrollBar/styles/grabber_pressed = SubResource("StyleBoxFlat_o2xwc") +VScrollBar/styles/scroll = SubResource("StyleBoxFlat_ul127") diff --git a/godot/addons/range/integer.gd b/godot/addons/range/integer.gd new file mode 100644 index 0000000..8e22f1f --- /dev/null +++ b/godot/addons/range/integer.gd @@ -0,0 +1,20 @@ +class_name IntRange extends RefCounted + +var min: int +var max: int + +func _init(start: int, end: int, inclusive: bool = false) -> void: + min = start + max = end if not inclusive else end + 1 + +func length() -> int: + return absi(max - min) + +func clamp(value: int) -> int: + return clampi(value, min, max) + +func wrap(value: int) -> int: + return wrapi(value, min, max) + +func contains(value: int) -> bool: + return value >= min and value < max diff --git a/godot/project.godot b/godot/project.godot index f080d3e..8aa8e78 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -15,6 +15,14 @@ run/main_scene="uid://dttyp3682enn7" config/features=PackedStringArray("4.4", "Forward Plus") config/icon="res://icon.svg" +[autoload] + +PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd" + +[editor_plugins] + +enabled=PackedStringArray("res://addons/godot_object_serializer/plugin.cfg", "res://addons/phantom_camera/plugin.cfg") + [global_group] persist="" @@ -95,7 +103,17 @@ reload={ , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null) ] } +inventory={ +"deadzone": 0.2, +"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":2,"pressure":0.0,"pressed":true,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} [layer_names] 3d_physics/layer_2="interaction" + +[physics] + +common/physics_interpolation=true diff --git a/godot/resources/items/key.tres b/godot/resources/items/key.tres new file mode 100644 index 0000000..563d74b --- /dev/null +++ b/godot/resources/items/key.tres @@ -0,0 +1,12 @@ +[gd_resource type="Resource" script_class="Item" load_steps=3 format=3 uid="uid://cqfnwpmo4fyv4"] + +[ext_resource type="Script" uid="uid://bqprls343ue6e" path="res://src/item.gd" id="1_7ur50"] +[ext_resource type="Texture2D" uid="uid://djmxd4580q6xs" path="res://icon.svg" id="1_ykwyx"] + +[resource] +script = ExtResource("1_7ur50") +name = "DebugKey" +description = "whatever" +max_stack = 1 +icon = ExtResource("1_ykwyx") +metadata/_custom_type_script = "uid://bqprls343ue6e" diff --git a/godot/resources/player_inventory.tres b/godot/resources/player_inventory.tres new file mode 100644 index 0000000..fd529ef --- /dev/null +++ b/godot/resources/player_inventory.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="Inventory" load_steps=4 format=3 uid="uid://bllq6ri54q3ne"] + +[ext_resource type="Script" uid="uid://bqprls343ue6e" path="res://src/item.gd" id="1_uptie"] +[ext_resource type="Script" uid="uid://dh4ytedxidq0x" path="res://src/inventory.gd" id="2_1njko"] +[ext_resource type="Resource" uid="uid://cqfnwpmo4fyv4" path="res://resources/items/key.tres" id="2_85a8j"] + +[resource] +script = ExtResource("2_1njko") +items = Array[ExtResource("1_uptie")]([ExtResource("2_85a8j"), null, null, null, null, null]) +metadata/_custom_type_script = "uid://dh4ytedxidq0x" diff --git a/godot/scenes/inventory.tscn b/godot/scenes/inventory.tscn new file mode 100644 index 0000000..d0d9f0a --- /dev/null +++ b/godot/scenes/inventory.tscn @@ -0,0 +1,57 @@ +[gd_scene load_steps=6 format=3 uid="uid://bshvduqysqivm"] + +[ext_resource type="Script" uid="uid://ct5na682hxc6g" path="res://src/input_listener.gd" id="1_qw0r6"] +[ext_resource type="Script" uid="uid://qvoqvonnxwfc" path="res://src/inventory_ui.gd" id="2_hj2ta"] +[ext_resource type="Resource" uid="uid://bllq6ri54q3ne" path="res://resources/player_inventory.tres" id="3_ty45s"] +[ext_resource type="Script" uid="uid://c62nslejr74jw" path="res://src/h_item_list.gd" id="4_yyk2a"] +[ext_resource type="PackedScene" uid="uid://gn8k2ir47n1m" path="res://scenes/inventory_item.tscn" id="5_uae8j"] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_qw0r6") +action = "inventory" + +[node name="ColorRect" type="ColorRect" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.10748, 0.10748, 0.10748, 1) + +[node name="VBoxContainer" type="VBoxContainer" parent="." node_paths=PackedStringArray("item_list")] +clip_contents = true +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 4.0 +grow_horizontal = 2 +script = ExtResource("2_hj2ta") +inventory = ExtResource("3_ty45s") +item_list = NodePath("HItemList") + +[node name="HItemList" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +script = ExtResource("4_yyk2a") +item_scene = ExtResource("5_uae8j") + +[node name="Details" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="Status" type="VBoxContainer" parent="VBoxContainer/Details"] +layout_mode = 2 + +[node name="ItemDisplay" type="Control" parent="VBoxContainer/Details"] +layout_mode = 2 + +[node name="ItemDescription" type="Control" parent="VBoxContainer/Details"] +layout_mode = 2 + +[connection signal="pressed" from="." to="." method="show"] diff --git a/godot/scenes/inventory_item.tscn b/godot/scenes/inventory_item.tscn new file mode 100644 index 0000000..a13a3bd --- /dev/null +++ b/godot/scenes/inventory_item.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://gn8k2ir47n1m"] + +[ext_resource type="Script" uid="uid://dt67n4jti376d" path="res://src/item_ui.gd" id="1_letey"] +[ext_resource type="Texture2D" uid="uid://djmxd4580q6xs" path="res://icon.svg" id="2_y87vu"] + +[node name="Item" type="VBoxContainer"] +script = ExtResource("1_letey") + +[node name="Name" type="Label" parent="."] +layout_mode = 2 +text = "Test Item" + +[node name="Icon" type="TextureRect" parent="."] +layout_mode = 2 +texture = ExtResource("2_y87vu") diff --git a/godot/scenes/level.tscn b/godot/scenes/level.tscn index be053a8..905ae20 100644 --- a/godot/scenes/level.tscn +++ b/godot/scenes/level.tscn @@ -1,14 +1,24 @@ -[gd_scene load_steps=9 format=3 uid="uid://dttyp3682enn7"] +[gd_scene load_steps=14 format=3 uid="uid://dttyp3682enn7"] [ext_resource type="PackedScene" uid="uid://crbrniwi6kd3p" path="res://scenes/player.tscn" id="1_2q6dc"] +[ext_resource type="Script" uid="uid://csjccrhj5wnx7" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_3d.gd" id="2_klq6b"] [ext_resource type="Script" uid="uid://ds8lef4lc6xuj" path="res://src/door.gd" id="2_w8frs"] +[ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="3_b121j"] [ext_resource type="Script" uid="uid://dyghf5fq7s72x" path="res://src/interactable.gd" id="3_w8frs"] +[ext_resource type="Script" uid="uid://bd046eokvcnu2" path="res://addons/phantom_camera/scripts/phantom_camera_host/phantom_camera_host.gd" id="4_8c41q"] [ext_resource type="Script" uid="uid://pdpejp2xor23" path="res://src/persistence.gd" id="4_mx8sn"] +[ext_resource type="PackedScene" uid="uid://bshvduqysqivm" path="res://scenes/inventory.tscn" id="8_b121j"] [sub_resource type="PlaneMesh" id="PlaneMesh_rd3vj"] [sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_w7c3h"] +[sub_resource type="Resource" id="Resource_olg7q"] +script = ExtResource("3_b121j") +duration = 1.0 +transition = 0 +ease = 2 + [sub_resource type="BoxMesh" id="BoxMesh_w8frs"] [sub_resource type="BoxShape3D" id="BoxShape3D_mx8sn"] @@ -27,11 +37,33 @@ shape = SubResource("WorldBoundaryShape3D_w7c3h") [node name="Player" parent="." instance=ExtResource("1_2q6dc")] +[node name="PhantomCamera3D" type="Node3D" parent="." node_paths=PackedStringArray("follow_target")] +transform = Transform3D(1, 0, 0, 0, 0.707106, 0.707106, 0, -0.707106, 0.707106, 0, 10, 10) +top_level = true +script = ExtResource("2_klq6b") +follow_mode = 2 +follow_target = NodePath("../Player") +tween_resource = SubResource("Resource_olg7q") +follow_offset = Vector3(0, 10, 10) +follow_distance = 10.0 +dead_zone_width = 0.5 +dead_zone_height = 0.5 +show_viewfinder_in_play = true +spring_length = 10.0 +metadata/_custom_type_script = "uid://csjccrhj5wnx7" + [node name="Camera3D" type="Camera3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 10, 15.3526) +physics_interpolation_mode = 1 +transform = Transform3D(1, 0, 0, 0, 0.707106, 0.707106, 0, -0.707106, 0.707106, 0, 10, 10) projection = 1 size = 15.0 +[node name="PhantomCameraHost" type="Node" parent="Camera3D"] +process_priority = 300 +process_physics_priority = 300 +script = ExtResource("4_8c41q") +metadata/_custom_type_script = "uid://bd046eokvcnu2" + [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 10, 0) @@ -51,30 +83,34 @@ shape = SubResource("BoxShape3D_mx8sn") [node name="Interactable" type="Node3D" parent="Door"] script = ExtResource("3_w8frs") -[node name="Control" type="Control" parent="."] +[node name="CanvasLayer" type="CanvasLayer" parent="."] + +[node name="Control" type="Control" parent="CanvasLayer"] layout_mode = 3 anchors_preset = 0 offset_right = 40.0 offset_bottom = 40.0 -[node name="Persistence" type="Node" parent="Control"] +[node name="Persistence" type="Node" parent="CanvasLayer/Control"] script = ExtResource("4_mx8sn") metadata/_custom_type_script = "uid://pdpejp2xor23" -[node name="HBoxContainer" type="HBoxContainer" parent="Control"] +[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/Control"] layout_mode = 0 offset_right = 40.0 offset_bottom = 40.0 -[node name="SaveButton" type="Button" parent="Control/HBoxContainer"] +[node name="SaveButton" type="Button" parent="CanvasLayer/Control/HBoxContainer"] layout_mode = 2 text = "Save" -[node name="LoadButton" type="Button" parent="Control/HBoxContainer"] +[node name="LoadButton" type="Button" parent="CanvasLayer/Control/HBoxContainer"] layout_mode = 2 text = "Load " +[node name="Control2" parent="CanvasLayer" instance=ExtResource("8_b121j")] + [connection signal="interacted" from="Door/Interactable" to="Door" method="_on_interact"] -[connection signal="pressed" from="Control/HBoxContainer/SaveButton" to="Control/Persistence" method="save" binds= ["save1.sav"]] -[connection signal="pressed" from="Control/HBoxContainer/LoadButton" to="Control/Persistence" method="load" binds= ["save1.sav"]] +[connection signal="pressed" from="CanvasLayer/Control/HBoxContainer/SaveButton" to="CanvasLayer/Control/Persistence" method="save" binds= ["save1.sav"]] +[connection signal="pressed" from="CanvasLayer/Control/HBoxContainer/LoadButton" to="CanvasLayer/Control/Persistence" method="load" binds= ["save1.sav"]] diff --git a/godot/src/h_item_list.gd b/godot/src/h_item_list.gd new file mode 100644 index 0000000..c7f0c2c --- /dev/null +++ b/godot/src/h_item_list.gd @@ -0,0 +1,75 @@ +class_name HItemList extends HBoxContainer + +@export var item_scene: PackedScene +@export var max_items: int = 4 +@export var buffered_items: int = 2 +@onready var buffer_size = max_items + (buffered_items * 2) + +var items: Array = [] +var create_item: Callable = _create_item +var bind_item: Callable = _bind_item +var ring_buffer: RingBuffer + +func _ready() -> void: + ring_buffer = RingBuffer.new(items.size(), buffer_size) + ring_buffer.updated.connect(_on_updated) + + for _i in range(max_items): + add_child(create_item.call()) + +func _create_item() -> Node: + return item_scene.instantiate() + +func _bind_item(node: Node, item: Item): + if node.has_method('bind'): + node.call('bind', item) + +func _on_updated(_current_range: IntRange, _previous_range: IntRange): + _update_display() + +func _update_display(): + var indices: Array = ring_buffer.range().collect() + + for i in range(min(indices.size(), ring_buffer.capacity)): + var node = get_child(i) + var item = items[indices[i]] + bind_item.call(node, item) + +func add_item(item: Variant): + items.append(item) + ring_buffer.source_size = items.size() + _update_display() + +func add_items(new_items: Array): + items.append_array(new_items) + ring_buffer.source_size = items.size() + _update_display() + + +# inventory ui +# two parts +# * list of items +# * selected item details +# +# list of items is a window into the inventory +# eg. a list of 5 items with a ui that can display 3 where the third item is selected: +# [1, (2, 3, 4), 5] +# +# add_item(item): + # append item to item array + # if new index occurs in display window: + # bind element + +# remove_item(item): + # index = find index + # remove_index(index) + +# remove_index(index): + # remove item at index + +# move(direction): + # if direction is left: + # move last element to first + # else: + # move first element to last + # bind new element diff --git a/godot/src/input_listener.gd b/godot/src/input_listener.gd new file mode 100644 index 0000000..be1d928 --- /dev/null +++ b/godot/src/input_listener.gd @@ -0,0 +1,13 @@ +class_name InputListener extends Node + +signal pressed +signal released + +@export var action: String + +func _input(event: InputEvent) -> void: + if event.is_action_pressed(action): + pressed.emit() + + if event.is_action_released(action): + released.emit() diff --git a/godot/src/inventory.gd b/godot/src/inventory.gd new file mode 100644 index 0000000..48500eb --- /dev/null +++ b/godot/src/inventory.gd @@ -0,0 +1,17 @@ +class_name Inventory extends Resource + +@export var items: Array[Item] + +func _iter_continue(iter: Array) -> bool: + return iter[0] < len(items) + +func _iter_init(iter: Array) -> bool: + iter[0] = 0 + return _iter_continue(iter) + +func _iter_next(iter: Array) -> bool: + iter[0] += 1 + return _iter_continue(iter) + +func _iter_get(iter: Variant) -> Item: + return items[iter] diff --git a/godot/src/inventory_ui.gd b/godot/src/inventory_ui.gd new file mode 100644 index 0000000..ae70371 --- /dev/null +++ b/godot/src/inventory_ui.gd @@ -0,0 +1,9 @@ +class_name InventoryUI extends VBoxContainer + +@export var inventory: Inventory +@export var item_list: HItemList + +func _ready() -> void: + print(inventory) + print(inventory.items) + item_list.add_items(inventory.items) diff --git a/godot/src/item.gd b/godot/src/item.gd new file mode 100644 index 0000000..7ad45f3 --- /dev/null +++ b/godot/src/item.gd @@ -0,0 +1,12 @@ +class_name Item extends Resource + +@export var name: String +@export var description: String +@export var max_stack: int +@export var icon: Texture2D + +func combine(_with: Item) -> bool: + return false + +func use() -> bool: + return false diff --git a/godot/src/item_ui.gd b/godot/src/item_ui.gd new file mode 100644 index 0000000..e5a5ae5 --- /dev/null +++ b/godot/src/item_ui.gd @@ -0,0 +1,8 @@ +class_name ItemUI extends Control + +@onready var name_label: Label = $Name +@onready var icon_texture: TextureRect = $Icon + +func bind(item: Item): + name_label.text = item.name + icon_texture.texture = item.icon diff --git a/godot/src/player.gd b/godot/src/player.gd index e1acff5..26bbca9 100644 --- a/godot/src/player.gd +++ b/godot/src/player.gd @@ -38,6 +38,7 @@ func rotate_toward_look(_delta: float): func _on_interact(): interactor.interact_nearest() + func _on_fire(): if is_weapon_ready: print('firing weapon') diff --git a/godot/src/ring_buffer.gd b/godot/src/ring_buffer.gd new file mode 100644 index 0000000..42592d7 --- /dev/null +++ b/godot/src/ring_buffer.gd @@ -0,0 +1,69 @@ +class_name RingBuffer extends RefCounted + +enum Direction { + Left = -1, + Right = 1 +} + +signal updated(new_range: IntRange, previous_range: IntRange) + +var _source_size: int +var source_size: int: + get: return _source_size + set(value): set_source_size(value) + +func set_source_size(value: int): + assert(value >= 0, "source size must be a non-negative integer") + _source_size = value + +var _capacity: int +var capacity: int: + get: return _capacity + set(value): set_capacity(value) + +func set_capacity(value: int): + _capacity = value + +var _index: int + +var selected_index: int: + get: return _index + set(value): set_selected(value) + +func set_selected(value: int): + _index = self.wrap(value) + +var start_index: int: + get: return _index + +var end_index: int: + get: return self.wrap(_index + _capacity - 1) + +@warning_ignore("shadowed_variable") +func _init(source_size: int, capacity: int, start_index: int = 0) -> void: + self.source_size = source_size + self.capacity = capacity + selected_index = start_index + +func wrap(value: int) -> int: + if _source_size == 0: + return 0 + else: + return value % _source_size + +func range() -> RangeIterator: + return RangeIterator.new(IntRange.new(start_index, end_index)) + +func move(direction: Direction) -> Result: + if _source_size <= _capacity: + return Result.err("source size is smaller than buffer capacity") + var previous = range() + _index = self.wrap(_index + direction) + updated.emit(range(), previous) + return Result.Unit + +func move_right() -> Result: + return move(Direction.Right) + +func move_left() -> Result: + return move(Direction.Left)

7F|KGB*rUJ0G^2NGTBGNd4i2xtBw_6ZKF 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 Zr;80l#Kucx>8VaWkM8SeRH|8q{y$8cqYeN7 literal 0 HcmV?d00001 diff --git a/godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png.import b/godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png.import new file mode 100644 index 0000000..a5799d3 --- /dev/null +++ b/godot/addons/phantom_camera/examples/textures/2D/sign_prompt.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bloouh2jtndx1" +path="res://.godot/imported/sign_prompt.png-18d451127e1cd1a16367acd23cec47e5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/phantom_camera/examples/textures/2D/sign_prompt.png" +dest_files=["res://.godot/imported/sign_prompt.png-18d451127e1cd1a16367acd23cec47e5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png b/godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..4aeae6c6aadbee8c0335d4134fb372c403aa46fa GIT binary patch literal 2861 zcmd^>|4$QV9LFENWI;BkWyzA$z2903Jkw=y z01Cy1y4@c*N0PsfpDqoqufKZarR@WirP9_f%Y_ZK`Pmow6Y$#YOXuGFes;&T3y@FTQ$6Ht2#C#x!#0TYVxodZ83gJ_?>k?s17 zoTX8O#;O%UP1bnvK`8(gs~q3+EIB9kv~)woK;*I8Zn$xATi18GE-60Z;-WLu zZL=X)_S+wcx*<0XPGJ@)|Jl02mHdnBnQ}Q6Ux}nLk4fE}eBLKlxw-%Jwg~qXS9YM> zBMlFYL+!V-Bje%W$pfDFnJM6$idM1gT?Q}P$-7e+pG}> zGo;FAzfmj@DOXy(M##XM^y%rX)`Wj%B_gI4ivZZL1|Ftok-eL`?D+-Z^efhnglejt zQ%_XYw2xKW#}Zl=M`28N?wYTmCKR(PxR2Os2CS$XH?dvUV>|uJ5yre3l3D5W8XTq!vL>%I?DZN2yy$!) sSXf?s_(sPpj9I9O@FP4J;8a;JF3x4Daw4XaWc~#W^^J9&+K-R_3yfXaJ^%m! literal 0 HcmV?d00001 diff --git a/godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png.import b/godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png.import new file mode 100644 index 0000000..e80c132 --- /dev/null +++ b/godot/addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bj7h2fc5jx4ax" +path.s3tc="res://.godot/imported/checker_pattern_dark.png-70cedad2d3abf4ad6166d6614eefa7fb.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/phantom_camera/examples/textures/3D/checker_pattern_dark.png" +dest_files=["res://.godot/imported/checker_pattern_dark.png-70cedad2d3abf4ad6166d6614eefa7fb.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/godot/addons/phantom_camera/examples/textures/3D/target.png b/godot/addons/phantom_camera/examples/textures/3D/target.png new file mode 100644 index 0000000000000000000000000000000000000000..96fed6562974104c8764f7ad79acc8d46c4300f5 GIT binary patch literal 96068 zcmdRU19K%^wDyUOi6)tNVoq$FIGKrU+qP{^Y#S%G?TKyM#?AYEb$`U|s@}U7`st^7 zt*Tyo^$wGj7DIyn0S^EGkR-%~(_`Vi4Z+puS`< z2YE3;K-DDPF#rHgFDt1iB4#W3rT;&1e13j@@dO74{~BRnVBX)~At50@K0Xi;5noTwGipA0Ol5;?U92b8~a+>+5lGaYI8x&(F_&eSPol?ov}z2?z+3 zl$0bTB_AFh+S=MQH8oF8PRh#4uCA^Q4-eno-k6!0g@uI&1_rjbw-*-|cXoC-IXRDy zk1sDTv9Ym5MMZ6FY*trSCnhG=*VpOj=*Gsz*x1dGxPWFUmy^8 zc6Qd&({pokE!c?*8l7uZV~UK|#Uj=x81u9xpGik&zK`aq;>2c}7M?Sy|bk zp`oClAbENDl9H0XzP`@RP8AiE&CN||X=xG?5*;0#l$4a;zkk!v(3qNE4gj7~m78Dd185t=nD=R80CM6}6mX_YoO;Ucn zeNIPtX$1hdQOMmlsQ1fP3`Hqwzr5B%9Bq;Eu>nHT2A;=LmsF%U_$_8wo34fF<=wSk zYBj)O_9)LpbB8QncDV)sfCwNVETHJRa<*>fuwse^*b+$T3mqduecT2NGD@E<70Ew* ze(IbmP8gcFFso4<#P;8MN|NdL&#m7(mv8ca063zJau;=I^C%GmbXiLe4`+|Pif>z% zEuGuePbZ9-=|7F`-qw#^38QsBNAFK{yxw85xiepn?}&A>EBuKN^G!iVkMMs!hXBA} zO!o#o4Crd3x%z)*gXzNqHhfl^~OYg z72)Ru)DR}Fn#+E!XvSpAOuF(usiTxNsfPl(rRzHb%RNapBD35Gtg1Tk&ArUr=mEYu zDwcG;BaYL&3QF&`EZ*oYHv)=ncLe~zXIIUM*y@{?r-Hn2hZ*$;dFPZ3iGezxI|idO zQ{Q zxZptmNSD{X%v5cbS3F!+c<9*pq`K_@h*k^d8HQ2Ve*MnwdqCPfE;!*p05BCV#VF4< zS1fU!V0-dv((*LxpIp26RJKSBxh%Xsu^*6nAb{qW!R2O_bJTH0%EeV?umCff z%8SMy{!}Rw?kgLZJe7c0&r0)-I<~TVn*~03ytAkv+#h%)RsX-c%Q8fVVl;{<+@P;@{TWX<015n<|Ybll{OY zvJo%U7gm>I*>lxS_~WwVDm?=vU;s0m7O>=HS4bD?Obj@iH2QnlTA%8bX&A(Oi4CA2 zZ%SeDq8rxEbh(Y=RRd&1dQXE6!vi=hq_H+Q08G{M)|%q4crzk>Yuo@FWxN;7Sc51- zrQ{7DpjJ#LcK63I7I-XO^1rtLNEx)&AibVfSRfWH!LCDUX1}KfHb2)eIMKeC%KUNE zU+I}hZYvlyK!KvqyrZLtV4^1GW_6VO|(N%O}+o{|rLkvbr3Nt5RXQza#x zLpD~KZ8!lTN^qJ1LJt-dIXhY~Te9%yekb7xvf(O8>;T))I+}S*b6S9`mfsHqz&vIN z2*43^Lfu?jmN{Dms`B?22XtR(22WOPH4K`stOL5OY0umIFGT|y@e2U$3iRfG_Z6So z>Z02m0j^?BPV7orJt&dIE}Y-MeK%#xePYG7v)9JI=RpFxiW*KvbFLgt-DN5OTb0J= zeu;=z(1ou1t%86JqVLb9s2kQSuu<(0R}Os?2Ip7hB$qNe{m6h135y%Ks=&=_;?3^@ zfG3@?=`GB56Fi!fFcQF9$iUo}QQKt{|dg3q(V*nIWes`KI6j(}@p9PoqO_)t@9>IAy>+R?6rcw)* zayYkzUEh-L2jhTivhMTiqnfhFL+*yd(;ji%!bb32KRz6a$H&{ows5EU02n@8jqYJ` z41#xW|2GolhNzsYItT2wz0_mG0GRTWTwI~x7$+b5NqrG(YVgqt=MWvh(ScXK6hOyYTRCX|9;1#%Zb-o>u%u_S-Ced0cWCa=|J#AB3MWP=ds|0 z0;Jkt1$|8QckuGNE5RLJyx?ToMyww|aHaH-&G`~6*f z4Vc}bfT+1v>w?rh$Rw2@H0)&yIi=R!b1;T5P+Laqs0zYdPBsE{0I1%WTAGFy6@qk{f0iR z@46|kst45D@mVezHF$eh`)Eu7#@42&0vXn){^f>GdBqgK7lE#08Veo@3UUQ}KN_vh zkOs-+H`U)p0(Zas`Y^qoNp;iM2t+)@5O|~6*?&0tNGCHa-y%m+Mt#_|)`Au4GsZkN z#tv^uj%6}#`KBDQE^qmCh}i%9NL1Rg6prGy^Btnn(Ioi|ZYZan z_=mWA$`O=Q`Hc!JYdGytqX1V8nYOSgp)VOdZJytg&3d|RfWCI5!WQv5F z(F43|E!vm>@fYTBojn=Wf3ruJkr_m{0d1*@Hkewns&WkY+mie`4bk_+F14TW;BVc6 z$vXhfWYsD^XxIKVw0+E+e(>S^;6%(B@L0k^G6!KL-(qE|YG2Q?ltrRia5xn<4?jo1 z-eP#7R31(2-c6Zxog!dwvuN4qCvB{v5^f<_4g;HV7zp^2_cam&fH66%F`!0dXO4yN z3Dldf`exxLY)6BP>WlSw2!PYCrbIt_5ZRWW3hNLJYS*NKQNnZM`Yx%PGegL-G_d9|pb9zQ(ula`xVFo}_D@k)BZChd z1PKyp8_(0Bt~|rhd7#7~XAqp7bFRENuU1Y@DxTOSFGg)LE_0 zCz!|}dGoT(z4s8#;uFS5u6fm4k9I+5xloAmU5FQdF!8ZG+;5fEQB=PmE;U;9{ba-m z4N5Z-bQe75=5c!I16jCqy18CAY*+10h`6*{xbE$UZLYPjJ!~JB_Pu%v!YQ?hXhQ#- zvh?UZ87-Jm0Vd?X<5%fLX zV1F>^k)UytC+*p>ZHi-%O(kp^C|s#V5jynmqIA_@y)^n)4C~Ma=oh#Au0d0=^XuHM zX{H=4Q8?B@a>UkkT2o-Unm<98DI6SE zN*X6K!aB?oUg*gm8wtORiw~{ zh?7&Gu@q~q{n5ee_`Y*R;57GZnc4IDrDZky;x3ah97@*K;RlkAi1Rr0t=812-WK|z z+Iwkk&lvq-7^Mctmoi1ENw7OQ>%7{B_2a-TQAt{x=kvgI>eQKASav}DI|ev$lT&~$ zKB#CODC6S3(|ki|Q}nv30rU83EHdW)W!G!8?F8cEx5>QKz3(Pt3PaJ<@$nn^C8g|Q(0le<4GQ?6hRP|T+#9f<%ps!fV z0;eLqj#)NOj&9fib%>A<1U)li+)CjNw=9d4G>njeOVPP@G8fs3wWRX{!JQWJ7^j{@ z0yYZ9&_a~It?CaI5@e`deN`G7TDG=qR7&Va4vo%7?4QfJ*fI}CUdVJjg(uIEkEH5El^l3l;| zey}B6iqv(>(-Oh{S%hmAp{d$XGN-JC%_>v{_9Rx)VOn9TP}as9J-0LcBcvqlI~QRn zYu@=bM9}DcQp#|K+&@x=)^`rJx|#4pS^g@&=h5+0Pe!b}@8TZG9w3W7pANZ9q=kQ0 zAMQ6)Z7Y6%cK;WW>r9&r0RW}z;1R1X?I?30CvgkS_tv}tLLa-(?_ ztA#i|-FB>uunD06S}=AYsy5I1rXB#AY9U(Az-nz}Aex#Rh5>H;ohZjp31DzK*UvWh zv%J&#@e)8m37gne3j!NXpu>fn2db-7Q=$(KXhl^3E1JHvA>?g1@Rv~wcS!eOZl;F! zO=gCenr`pZsbItNb+|#Zz2+m1(Uge8yTZz^Th3ETdRE$`>;O))l1DUGfpfywkOfS) zNBNh!fUGM25BfBIF>gSvNrS0?7Qso=X*l>Y;|%W>4h@lom|w+2gL-`qOaOW~0Nz`* zdA3fOA>wcp4ajz)9GU}FTg`r7dnSY0I-{alqCiQLl|bQ3(Rk&yUB@8ZsLexiiJk$G ztp4b60pGXI*_}`}(@7o59;qdl;a5?Y)hSq#LZ<;(Q5j&HXFJBi3pdJR-o=^g2d}T* zVVmQdwvyu(ac<%@xC|%9%JIU?J~_!e4PJo@IzBC)S4~s(eNe(HE0=t&Z6W(syx34OFw+O~bFUIC7`JfRH$-Js{<#ze^%mK(qT*IjCGF!NiA6E) z?Xf=YL7;Yq%rlt>rEl0N>4Y-28MyiG+=hFz*k6_;;+s7!`wMtb+1g6vfR5?1ss*3f zM81HR3i%}WYMyYE@?9)gJE1Nt3C?5V*6?1r1@g(SDBd2#h$5|x8&?^Y*M;0t&G4%( z`M!J)ealCCiIU;KT4##)5fM#|n_R=iBiy0sSq%s3Nqd>+ynM~48JVD!SPb3D%d8yN zUPVowyd1Dux=ciRz_YMnwv7pzPP|dqn`E<$Q}Hb}uB^a7akw39w#W#Z9e%AO$vRo1 z{k*4bfr_^t;p$-+>M8%wl4lwOJ^4BPG5jvxNUgHF$KskOfz$r8Xje6W;7U_*Zsb?2 zF4ApK4<4RbU1cVA+a~7;)s$aleypa(Io8C+1x++`SjRW9AWqc|r6fP$+6-ctOP-?y zPYM6;D47rKCcHw^OQf^F8`a6!h6Jmw1Q&^Dg!K*TartL=1Y9CJ<79a6<#%#?NsUG6 z-m{}ikS`1On2P!mAgs1Vd24J`4M9YrD0x-q@y(>rIX4nw1Z3)0k{ncSkZ?mA)^OS} z^$-TGrYc8w2oz*tZ47n$uW-vw zauq5FB7*XZ6VNrMsX0-0Zir^X;I6|mp53XssDIt03nkJ8ryx#tn0$PHDV=?w;PmE0 zIdq$Rgj*{q%!&@OoM?n06+k_N=i?N;1fbcr^1_liQ=G%oB3WZopnwmmxd8n!q?=%_ zZ_NGmp>o{h*dwjyOx#Va6muSjIi&;p7A&9Q6+5cnM_}_WNsR9#Qg_GG=%BY0?&9U zQ2HjjLb|W~L{WM{uzqAe_!7ZichrW7u^wk4qJ3%ZMIp)oaay1l(-f+C_#-soY!Yy* zlSw&_5FUR`f(Gm*)*)V4p(yzj+D}(%8EY8TsCH`Rk1xRMoAi2nW^(gEO{O_|0$nhM`fwug_Bo)>KiN4X!aUo^g-~pm!xj z5dv!5Am6hP^gS2wDtko{tM+9`bzKn{v}}-a{aXaiLUBv9-4LX$fJ6oxD3hH!qN?F7 zHOxkw({L^j9AT}uqVyXKd|Ty8qxz`a{KMS(ViXl07%d!-}_eI(+&m&fKWWh zGs7r@tq^4cSI$1+pV$RU04H011BN8RNGF&%DynSHn~rw-ns#tS!<6NG?~JENa)>#K zpku_&WEJP4aB%8bBTAC=ltq9k_$-bm4K8lpIN(0@oR&EIOIM<^V`o1Sg4Tx_jwoCF zXDz3%9U6FVUn^1g80GRI8U}VUZ*3U1FVv&Pg(N$1U5?0f%scO6Roo45ve>3eLc!rS zWd&l|*TIq!rU$GYA({fwZ9p8MP$d}2yI+)+DEEl4e5ZdO+Gji_t7LS5*VoIL?nU%Q zJvg8ugx2C~M)%#oPq)$_S}jo$$9O~JxxJkr=$r1|oS+#&nNFSg;PAFy6DiZ0 zDN*CpOM~8N!r`Zn(8juctaM0$?i- z_eT%nJIwRov%9nO6 z!^v>we5J#D9Q570V za^jz0+m3&C&&RN^J)uIkJb@c_bNI0A(M?@SLx#}6aCsGo)F#h4-efGu-heMR>Ixls zE?>MuI;Fjhc%hLyB2;8N8=u!>U4$TrVWu9KAR7$ZF93)yfNktNOMqMOS;1!B(z+ut zsyUvGj{W^l5r|=y5wdAKCm6wBkBB|;ii#%m#YTYAQLXm^UAcdq96!FnW@ZjaB<9&o zHbT^Tjofqo5nD$;7A8`hk&dMrFvzfi=}$Lk^pN{E!lM2SHtLRqbX4o05kmFu9_fbR zgQWvDQ1G|^6UVWW91S4J%_lA^v<*$(R8;r%A>4;V+o&{G0Z>uG5=O|Q{zkkGYl+^p zi}AT4oC{Dbf7jXZx!&8r)Ac|b@ZodaB{Kro&F?YeBQGHK+Y0;ij2%${c;5c*f_O1R z!-s=Bb!gBZG-78upQ^9js`n+dKQGu@7np_m0pV+3c%a@Bmpai54FuK2 z+qf9JpaNb4!9q%EzYb<@)-V+Our&)>0=k{KbrIWEbb` z4EbaxC@Hx~JH29a!^8e@=%d6-L1+GRcb(#~^S$Z#zVcFCb@)_1Vyh)zjj^7hre%#; zA0jV#B+p%*nf;62CEX7bkQ+qeDW|WUC_d8`^YwVwz0YP$1gN1yG)~+=3p8(g1PEBW#Sv0^@ad?C^jzY+sp_4 zUvf~?J|_DhC%zLpn%*|v^9`{~Hk8?&`OcVk;l0_BVL4rh++7jQwJPJqHRF7P!27@a zO1IDn3A<|42bJj0y55stE>Rq*yCOrba5)s>T!7<0ZE)kg4pzZ2djTnv;~_ z>%0zT4BsE@kZS6n@fnmU|Nf!4xcu($%n;Hn14gD6Ev*p$5N{@J{vmlY?ny2751Wz< z6A39pX=fR!0u?{9pF>SD%q?0X_$-zLrsYOn7(Xz-XoPGM%P7Sa`6CI+ZB3>{R+uRh?)3law*-M#x)CwCJY)aGnkhv z)x~eJGg~k38wndm6BI|+7ng(ur&p~1i9h=DH|9A=3EO041RX@WIhSMUt3zuVHA1ER+_`92 z>>jf&)5SqfPNri0g9prVXbM<1i@C?5eM#N)vCNA8`hc=dIX?E=n=}l56#nzY8`JLu zqi5=t)@)TxN!X}^_n=J`28A(QhW=<8kIPZ>+Zd(mBK4E@#%xvY@3L086T#+U__#ZBGjW(=h(y|4kCz_Qcxw+9I9@lT z=27SG_&Qo*R}h{TEKaJ+0t)OD7NPp2xxOuz2d$x6<*9b$HBtF|pZ~t|TJ9-A>=o~X zJc}3I;#p5bt&9+J)0mDWqQ^xGj8tj~@9g3|n`adpyV`7SR*QpsR7J4qphAYExo;P1 z;V$WpwNxw3GPNco@=C9DAU!B6Je)4#+cQea;5;Sne&2s1JQF$7YB_sVo%&HLbI(_Bv!}p3fHCzw8{etQ68tA{;I- zIFD$#BqS0{TAm1LJ@Bd8$S|1eS|9%b=1>mjkskKlz#IFs$sZXZr>nMjgM`#f=pmp# zFZmcRmePb{Nq7!>JKdU#*7svHnjWOC=L`LdorC1qi&Y`3uV4B_H1D@|ipZSNaE-WF zzcSxX-r~v;Tw@{#`Ew9WFxmWBjjU$m;_?s%H9g*+2TfdjUeXRj7WnEDef7t9IMXjIqm_D@OL`^$9A^ zFl29&|3RfXwzo4yO)7;GK}L0?!fr0zI@eW)II6ZBQ4&Lz-YDowPeZY|hZ+oP-4#5U%xM_P#xo@+9<)tfMk&jrAuC->0hWb%@Rud8J9SlLSe0r_O#Wrbb@SCzzzFOwA2#(d@x+Z4e-d5%jJSyuzWFQWC*hyBXxKPtEZakK*)M zu`tfF%R*-o?x(fK(51kP4x08pby1`cugcLxe4lOfy(MACmK3)j+MPYNqkfjn`1hZC z7dhd5Rn8+9)p&mIhD(t4wpWOlxXVRTK2b}Vt6*J1&LIuqT*w~o>^hD|^J3!FaBuCc z+Cm^vw$`^@vmF=fCLHkL8WiD1ikd*fCqtGvq&0b^M5 zV|x5#wXZb6O;a6gM|uX_wHd#rfuvIcPv=uMNwO1q>@Y05*7v`hPwK|0s ze@(LjRPOkED``p(Ym$4V;z_Drne9)`1_hCSGaK604{$1Qw1s>p?E+{d$^O%$uweTW z-DIQ2nxd4M>=1xjIMo+~RACmD@@( z`!F0;Z4He)xusX{UyHztw`~*pa*PDK5!#UU5=g`)=-Tphrz#pSt7nfQSp) zD}osEq~>8N<&d$o%`_)=k@m2y$<#-PvUZn%n>CB`VAa$9#!8S{m#=u%i0~`S;Ro*q zF+5#;>uD(ojO1>{5>hJESjo-s-}@H%-O-_>h~on$S5FKz(}i!QF=J(dSdfLUGhK1cEaYdlH~@j@|jS~UvRqP&pdlADm*|oPd9%NQ==uyaCpo$ln)4@@ZU>R>kqjS(486euA zYeBmO+XJe7PM^`^PU)~v`=i|x>7HOgy++lPVcn>e@*EQwky!7?mpkQt4Nc8g!EzZR zD0D1}?sl`^p;E8X?TAOLUXjeIiTP5}d;x{iN_aq#F6rZwh`njgW9G`F zMP%#ciU{5oW@CI=ru7S{DOrqc>4<5Wb&L@~9q(lMaxhRBIRpCT+>2VN`ypnSx1WU9 ztz>gPDHapPVR5^j!t$OUKARJT96)Ndey5bTYe~tyiNf^F90=c3LuA`(LUNK1^L`zP zTu6C`<#kEq=lMAGFqEgMNXL+{FZ-o2(QRD^dXIWIY3yKA+9#^pUg;!p*pv$e$+{jv z9K>1|j{uuz-stKdKggL~1bf_m1*Xf1WvTCgx{4%h#>J5kna9Gx7s_bh%S-#~2!%ch zx^)4HFK74-Z@IiBf=2wFzs13>CZaM7gD}1-O9TJ$N zWS5WbCFgG2=p&BhLeF}+jRd1D%E(6NmUfO*j^7`+a11IK3_*3-5TpAEl{W-uHw})E z3^VQLH+g&1%hlmMD!y(f@0xa8UtOrf7p&bHT~a@Y8tZvGM_Ye1*p$*3h#8UKy^oshR-Jc;lfE@CG$BQaQtt{HrOFh2E(|%O1u@^tLKl-vUh;fIS+Nm z!;C4<83HrDFDAadbTdEu9%Y{w_i*3|bSrZoolG+A>|8QC6~tY99j#P}>FCL$%cULj z^}_K#rZ$#+M6^uo-W198P8-#a8Ao_T_y5h**K*-y;RNgHV+W^-0*xgZ`%ww6iBWzV z=T@ZsVLYfMI*wC?a$L-M=vqy5Xk0&EVjG9>@! zX&Xdt@U8NM^8u*c{9RFD)NRGj+sE!W2OtQJJm44M^6x|ITlEkEoq38Lq~1*3-jvp} zkF8)-8K}EzcwFn>JsMm)!-RY-UDeMc7>%_lpWFVufv%bEZ$+ZWof_c6fY%u!0~S@dYoA(BcGxt7`BzQ?v~vdeP1#Wz!V7Z` zaTWlGrYVIt25oLuCzL@*-MB1}=f-)AAU4@xR-iGhx5(+AlJ{Xt`PGKxJm@WaXz5fb zQQiji-2a~1k5ze@^9XjY-A-KIal%v{4fjO*hSVGEV9+9>fX|Oc zbn~2rsTse!F43*+-=>#TpS&F{^&n%nrfR3$2}HA&5mQtm)G3udV55+0+M0XZi&4BE3R4pnYP#+Ojd&Swh5afJ+ks+Y5-zmfEw@j1OtMl{Ia0 z%e$Q{FXxH12spm+pgR5>F?>lg&v6861{P1WSo5@u@2Gcv{Md8L zNhwtU)}YND*@{Q=z@Nhkf(#G7HB8bD+<@lp2T_mZ6aN{tSNKLW|3a9+d1xPunKk4s za;)@qkCPzqVP(N5qy@_Tau1d!2w!GwOJ^CX_n(F|#BVxT-&TOGcMKEffGt$$^mQ4Q z)4=L27gyLPCuQE;{QC_vi&S$*e{iTRwpSPRF%3eznXnD?KX%`)EON| zBMdRTZKoH&UY+6503oW#vyLL<_97Z~=vRLN+4c~-Y^Yfq78IfYb0yJB_NpF6KZhpq zp2!4o?e(3Cw6`Ki)an(lPP4QolUF{?!7pF>iI$&RL)^hjxl3Uu{a@{_4 zNIv^N6EX!s+lcX?AjR2ZQd zmQh0<1hFR{-*=->Qs$lK&j^PI->l3Z2>W*{H$}j6|9Ec>n9?rC9a&UWZGS2Rjfz7d zkMY8*>{4$XLO&W&w|1^uQ{YBXQ1R1qmj#FAs`{vKpl1A#k~(O$srkxLE=OTJg{j}j|4WfDejmO-A=WkB%&js4q*eK7Z)MtA?RljdpVE@Vmk zYMP#N8Y0otu?H{ScS8j44(%#^<1KTQ46 z=`Qt5xb+4Y<6^Be{ks@8w?4u{Q)1MvRjl~Jqmn5zos_96uZa@s_#!+^WxiSU>$MEf zu(WC%(j~qM(0rI5B2h<)O;)&zy_pO-BOp}kKQ5_#ira949-t=-*3eo9a5)fvtYJ1A z^y|z&AID$!I_ZuRo-x+Rx0iWP&t>Z-C4HYfKDAYq2EoPXr7mKHJ<*W7pBK|B7}O{) z(Y8tAvG3Ff7qQZ+hmX~at=#{hW@FN+rvZ;TdM2&Y*lCUA4iLmi^Ma|ZXoI;_!bXf1K1TW{^ zO5MwDwrjo;k(IXg%?ip1aV5A&>R z@m*@xHHvLFSIpexR!xT9vi({xFIM#&M_29i&GH>DnNjD_DN3ZWUMf>b@D~IBi^u03 z4Fnmra__&P^S=+GR)h?Cj~21a_00M24Ylc^61J(_m+MZw36X>?@B+h6vhh@P|S<+}A%ipER{TqLz zxaD{7QS+#diZZEs%;1gqEffS&i4c68dKdDdUT84}i-*$ZqlQPQNSj+e8`g;)qEP2? z^c{PCgQuLnZk5OC7pPT_(~@4gzy9OtYq^Z03i&>O&{o!H5{UX z34Tx6*#|!$0`7jkPMoc3+^jPKgTx-No|5%^aCMxHWcmwbPG-cSc)tpm5w6|mwzPGv z0=4HZ?ww?}&KNE>St=3C(W2gc+H1=CW1Mp}eJ-djUxi4rx@y291*kW0EB735t(9Dg z$9bV5@wD5HrKwxyE-3K=?=ap^<+SXXGd=W3yU_=3gCO4Eoa`v1#;O^`s}Za9*WAhO&T+vxn+S=EBDoNiB~nw+Xk^K!=TpVT zI}xV!fX^_yZU?0-Ll>G1Ibzr7ddHSumzKrQlxy6B#Wp1P#PYXFPkD?Kjn^GCyiksG zsL8&eeg%m@UJ_3E-?U6oao0?AJ(RZ_4nl6?nluLBX4jl}p==hAXd@mw_|%J3SS?#6 zHsMLmFeMSM9+PpwiKR0`nLBpZVP)4u!X+}Q~$YNSrdzvDW@(e#QKo9E&%x6JgA zkKQFU$RGb?pvY~TYr-O_YLn+>3U%(@>o$6#MVxilH4i>7c(-oUb)xf^)5XtTgqV_8 zsj}$0rTnU|{)0`QM#j#EZ{YT|CX4b~3GuHpczvBggKH)vUa3j(-Ph`!Io=I`Pz<#^ zI{mS)KYfjR!=SRKW~bzVG)MMGa>pbsoS^@RTQh0KZf7qR4~4E5tQE#$h?ILUUfTYv zGMfGnLQygDyPRR=E0Su{*xz5`y=00ZQ;>DXX`1CmWjf=EC?y;Y#|5g13KoxYpmzmgDBR~=inF)M>5G#q z8r6o~$FxRsSWC$Iq{D&a6XZr8{BABYrFYdDM-@$|S3{N9Arwy-TDs<COLKbQl<_EzKL1p-MrYe^(ecXBS^K zRiQh{M(0~cF{+rmUg814>*V$BU`9uPgk79B+=`gTN6d!QW42f;(WRvbh4~#nW_*yW86Av`o4(JF>mTI5=H#<%f-u0X@b-6= zAc@Y1J8b25*9@JsIvkfBzF*w*ylm(b8W&bUfZZqkFr&eq4^p9^LpmN4o!krH(>gR;=H3VY5#`bF$>EV>cYxwUwi18_6u8qUPOIEfh zA9c@yS7Vm&yFlo3hxj}5bhX@9avYz|&bVpL0*EzS)_oG;aUMtHrFt);BImF_0)F3xv-JD*k=OOK^zA(_kC@;i^C0dTJq!Q)`a|iNn4ZrIN>xLW zG!2CyAwNWMaf#nINuC>8iG#h0rRX1e3QEmPAlF!bZ4h&^R1H-BW?1J;A{{UwIW6Sz zY6>?l?Q9}vg9*Y6e5F*#aw9^!NBPlgo0;BqS4 zu9mGUHWlFCwyprTiEeHlcXVLct3Gkrgl=|oygYsB3GJ#scQm+J5jrEB{dFuX#K zk44oO?bz`HJRIEr#!%xN(f11OmozQnGE585XNy{>Awd!9OZohh*0=ewh&zGPBEC#8 zHcbz2DNnHdk=PPTxHskYLo6Jd8s3h$c#r&=y%OJGI3tQ5i*0B}swBDJ_ z?w<3X8cF*u=W8=a*5)(%?Y+GH7nFNOwXV_ELg%&K2WQCST!Za`}f6%h&H1VMyzVs=x{UR zsyDG^a*#DxF z^D&>KWf63VqAfZ?N?tlr%lG9)yjvZsLi7`a4fTeejdMCZz5d$Hg-O>3r6lxJ!o;Vu~PP)M600ELd`q;IXNQvdi#a$IC5^Q_tuDx#@w-KdU&*^#MPmO4>TE*1( zBgnrSkJ?Q17N)J>w{D-L*-`1=qC(VfOOX7s0IlyeK}IYbtzx)dx;&SyK(|}nc+L$R zfu@UAL2XLj1R4J8?a)L6{~lObr0x{VyzI*(-julaPrP3_|m9qWCDhqyB|Omd(ms%R+HpKo52n{NIWl-2pt0n}>q zVi_>D*EwV!SauSyoxfoDK^RkB%aflz5i3+PIg-+DrI*-~RrQ9Gmo21_Q{Mw$>F`}6 zpR*CE$dUJ6lE`Fk^6k3EOAjyv;Z!hOc+f6D2^Cc&TR9%aGYF{Gs^6=ajmr{+ z@R;n?X<-=E^b;@c`XeB!)e1kv+rq7o6T3>y2YA<@52zL674J%uGy8HXQ4qoH?Wi(;&+S_s~mq zc)wD=PN;(Z+$$X^-$}K*Dc!e3WOinrPiQ;XuA-7*TRI%)Ego&O4Mlz{7M6UK zS?HuZ;nGQg+xV9*jea#5PkZt!#pJAD7C>0aYS33x0;er5wA-IJkr!=X;_s0#dv3Ix z{cjbSo)VE$%Wt03dLWRqOo1IM&u(X=h*YZSn8Sq39=D3ys?$90%Ky7)W~07SiWz8) z-W@Tuo*)sOAB(s8n3WK}39YFQpC0|Pm_^5r=7sNm8TzUd6QYc*)kZaNG7NW2xUaGQ z_uN;7KHl1s$3;#5^fSL;sj&B?Q6D%j`bc+_;RHPUIm7ykHX;xgNRBaGF8?YH~rHxd^~ zuZ=q;cWwSe%&i4pJ-?>MKtdcjRk}2X+{H?P>;9C=_~`i6pw9Tc8?sUA?q7}#oPPi< ziEN1MxtunR%;6#UoR8gqqbScu?i026;ThF1w%C|PGv5uM1}(8KAV#XQ>)|HQXYo04 zN!LlIL?g3oA7V{aAfPaHx$-}qi)yTwYF6Dws;34sQfftJBsNy9ehS(=&8QT9wYSE* zm!vV02!hfy$TorZ{m~}MRITF9B!?>YhQVL$t(0#j6BnY^aBXD2TnOEu*U_1?^1*1V z@0w>+{<}H4+W4`1l|1qxe{aYKYaN{?E7mbKpWMH0M!|>stM}%xQ@+f*I9Lxo(J&R0 z>#5HIZV{B{QIDw(E2VNP;=(Ei1UoRU{~kmpx~)B6)8((H8rhwexFvuPr*lem%N z3O+t%Se`F*&WC`7ORxO)-~)W^_rH%PsgYDXg%IFRt>3{*MBmaj9l1^TUMuBj6iwy* zQgC0AeN+duhg_h*%BwA3lKNq_{{+94#kp;wFLV_P6%d5U|8Da=$0u)+@P7byK#9K< zJ>%OP12H+_M_=`Br)C1&J2id|v4RH-*egf!`RD8CpJx{IWlSx`uY1bC=(5hsUON5=JSbxiQPuVU$Q^mta#A->m- z!&)DIrJXEx26$)&kN8knqxz;&+;a3dIw)E^Cg=_$`aL~+Zn{XAbYB5Pg56;k31dWm zSl$lBU*{B*P;^+kPR|(v6Y@dWzt=;yY#pO80z`%$7jKT+^yj&p&ei+u>(-)$=y3m; zKgow+`+g6(lFfqvk)x%`L)Q3Qzi0D|;AdZk7K#SXtkQFZEAjzYcf~=X43<+80gY+4 zY5)Kr07*naR3b@rv4g~MO@9U2HNCICm_Bzp+;34Te@mZr-a(q&H%>hSh%61C+s_>7 zRaxq0+AcWZkUn=h+;4@S{!s8!_LF2FltDEFi1^Q0d9MBJaa7(+eS%{(=yRvT{lApS z2Va@}4Ef#!r4S$*3^;fn^Od}n3g~kO#SZs2`3w3p=F?+lK|6I2AUfof*`GRkLEcEs z^tsdFuGirnlwYPWWj;He9HIyUM2|uH`=38hx6whpl{w6Fr^8)-Mb3>(>#331q5#pQ z|9kVN;PNB%O6YT^!(EN9)uZlez<6Q|9;5sLM4QQ=@kEl_r*0y_sb%!JN3z3xqn!P( z*NDelm-V#Rc97Z!5PcfHHJ(bc52+tB>aCAlmxeBi7|ZmIjR(a;t~=j&QVi!%`2b>p z`Cj+@0dWgm(rX9Vf-Z^_Pd_4Oef7t?O*{X?-no7?d1Ya|T3f_Rt#;a_w%%J?r`pjq zI#bLF5D0`M5-=nr1W7Cg!w5u?n}SpYL_qSg|4yx-4yEuA-6d^u`Gk$jww!0MwfBRE< zj5&`G1tZEs*%74@Jfb9@fm`weR7R0uKVJDX`1j1oPSL?otxsjfBScA3^|Bw$+yO7T z1?<(ZpV}xAEZYNTc_X&3Rmq+rR#V4xM~KptRf-NPSF^Cq(*(ETdzMihMS$IKhQAN~ zt!Wn>2rsoW*Ab#T?HQs2%K-RHQw!XRFQ+;RpO3b{6+Gr(JDTVL&zealIzpBPhv?of z*RhRL;6YpPm8+fsiA2lY|7tW88S zdNa0{{UNz!O$J9h6S9P)=>&%t)daS2TF@3eaUT^@n0$+7^GEs6KGr7qt&ipb6I^Ul zI5^&Bn|NSuHQm-derg$Vxt-2Ojek;|KEn*W%v zwT%xJaus76$&+)`*u&$qD$o}ETPmdR_yNwv#-UxTS8(*Z*ud--YaBg$+&|g+Tl3TV zH=T`<*?THOqx0tdr_H~$P98a4&T-x`NAV-MF~)%1(!CDt^EzQQHBwkZ2zQ}*SQoT| zjRZ1M%8*Iwk77+FBAIa0eAM2eI={2-2=_~=U%q)Uuuk6v4N)IB(h=f z8oF<#N(!9~XhR4uLqAeWbBPUmd40@kOLYs_aO7o&{mgI--9D%*ui86a9%;y@b(V;- zMzNs=yWuEYL-!RMsFOnGM>OX$Bm0)%2BX#-<}}60YH*k`T#d2(DmC3{(HXt0i(i7n z^1EV#%@gQBT&-x!y^T64RQ4r++1dr|T4EcFs&ZLG(xg@;XrUX9 zqD_6?%T^7cuodklssz}ldJQrooo0e*EPAy2%(bI}TmPqw+4Z(-v~%=uT$Z_W48_1k zft&ign`$X|R;>iHvLD%{hGoXNVK#4%5+{9n`5i9@$H}I9(04sy#SCOXNDEdxtVN_#wy_X$7B21A^=5DzJY?DH;k!gu* zshEP~Q!sbB0PIe=A_JV-$mA8#pli#u8V<)jn$cQE33o#zIWKc?&OKn0*ud6$GZj;C ztU)_00d^*b%sU+~Ggrju{jYuaFnLR*-CWFF5i#njMedUGz$QVP$Ne{IreIk19WMx# z!YlIov72Sdk-8N$+w&-?W|L_(@xCxZ6o~AIrS0P-p;GKwM%5Gq%fVc!9@mowGbP40 zmS07rJf^{H;jQ38_k}K#kIk|oK$^%xEYAsE5-P=KR84`ib3HEz6{5XDU|>@>F=d6F z@_hGtG?Y*Qh^&V%j#JKu&7{PG^iJT1r(l~CAy#ala+29&^f9gvH3(p9fhXF(FUlYjE}U1+10+2enfm ze2Hb%r?BpGtx{YtV|USzs;-O{z88%2L6%GZj5{lM>g3h`0ndE~yR-e0>L~!efU>Cv zcAjw6RdJ!L^CxDgU}-Rovg#^2jOl!QS{N)NPI3DHckXizR+GdpsGb(*2Q24-y^<0* z;rZ@S=BJ>@x7B7-2St-iyQ7`^EGUi+iQ5Ig!WzSYwa}}npBCfey-*e%fOVaF;=t@vvR8t(odI+_f3Tk1tZ-KI>5!G*sr9B`t^fNC7 zN`cXuLe-;iiXGLn4Qasm48qK>>4g=$Q0u&9J2jM`Avry$Uei7%EPz!OGb;tg2{YBz zQfVyHS?<5UICW8&@oP}8iBn6V*7*}^C^@HwV3WT4!PE+VCCGIXZ zZwTxTTiP4vA=C=dL8wYi4$N7QLr^}`iW zP1I5IasbJaYSglyURkg6Q<|8I7NN+-jtsGd*5c=>>tYyX6$`@7%xQr7G+Rd9cw`6 zA0+pP3R<2r=Anf+*O5mp6RT8roZ=2$h;dni21<)S>kFXXbZ(}Snw$Mlbre3(m~~y& zMUKK7-(9kW)*bhL>0QIDkGoSINJbOT|)9bX7!qwe;W}ta^W~!uiK_O2!$Q?W1 z^^`@Fng*?C$bl;3TthWA$CT&4Bbjgl(@(BdONv%4obEhNQgX0cI~FRJ@hJE0oD{W4 zGITZQnLE_Y$9K!9r)IGn$$}3ty(CRkdt|o1n&*_VC7p@|4@1j1_wJnNC7JmqXnPK* z;UAw-Prc7K-vilCa{|*zBz+62Cz*NXJiKCEJ1kB!kFn-LR70$0OdCK=%-QuZ71ev} zM)DCoXq*xhrr7>!F3#x;lqtxhXEbmZ&qh>3te-J$(1oU~B`>?kS(4<8lIzM&HID0Ue03Az_)RQ$iGsiw1iB`?vVOzM!F2=(Y0GtLZ>Z5BQo z6oksW8UGq*1A7 zi}#r)@NPNA?ZS*RNP~+GQdPZU)e0cXVYa~PSBZ&EH<@{+Q?6rI29anoin+U|akNy7 zX;a!DEr8SvYvo7ORd4wxkl{)(57^}ti4J8k*Sy2WyFtM>g;q|{nMT$B#8}od0%-xH z7BC-DSG{4wS2$+VmLobw+8HsS=@Q>qy~{X`(^Mg{=`?d3)LV+4im~fe$QrwIKo8MZ zY@o7w%{Cy%xCa@Tu8Rpwwfv-iLy0My0z^KUIzH)mL#muW)&XgNT%Z-+L1pz98xwJi zRs(rIR}31Y z1SLH)%g|og1Ji>xHz^Xv(5O77v_nx7QnI)+tmrX_E8ci*q6ecBk4Kl2GxdCwT z(>i&C1;kpQ1FYkSCmurXlQPGdSITSoa4_ys+u7eesV-B7F>4UVuK9R`1;pn#*1CZh zii9*j&b$)$Nu^;xMR`FEA67l-jeBS46*8G(0CDl3;H>XD9$>-P3bMlemW(*$X^4Ay zWv9F%ZzPtrF5dm2SV$=%Vp;DooH~VswLHM0D@2bz8Bdz?PElS_R*>luE8a^I&&g0& z>RyG&vBuPMIG205?3aC2c10GIMNmKlqeYE^3ldb^8jBhcQIIHB z{qOoiPfuG`1n7EIU!+`9pqbN|S1ef24)fd!m!PwTg! zKA!8V;bhHT2|tIzPQMXS+hoClO=&#lFRO*62G;ap1h~Wfj0NrKFL9eZ#*>4p9)zDq zaQCp=AjvUt_WS^k_;5RhUAI$MpkD~PcoC3kL3ytCdd(cYsoL5u{GSLU*LsbUIujMv z1dsSGP7BNHkA$2ZSTBM7kB9-?sVQ@sHuAD{b5M8-B&3$9!r~$V9E9MEhkl?2R&*nY z*Mg59u+YEC@tHG@x;ckRNs#Fm;s%jCYI2dn$(9ogV9}k7Fq2$;!j|exHHg&zeeHri+P_ zDiwrZhNlxQL#D*Qwua#MINHx+jupkkIxMhuVtoHK&h>K&_=?kB?lD(1pHrD2{BoRg zc|WJtz{b%6-aJGGhTIMQ>Z@2x1M5);=lM7IdeiE0|JAq_UkSewg&ub{lpARK-o~*W z8dM7_YO#T0o484w!p|6Yr~r@z=;;q8se`Cir z9*?wAsC~y%eYJ1_#VokRG9@Ya`l{PkUI^z$R1OH!kHmCmi$|;Z+K1asQ>qqL6k;jG zD(7$_Q-n_o&NlhwoK}!1{#Z?JsEF-bfdiq&`<)2h+9rN|@Pz%5`-E zdQT7BUI__0_!1 z5PP)In(IgDueTrk?g8b(TzphU{*|7@w$1QivsHlil@JZIXZrY z`!hdTAhS(rUzo+m;&DH*^&{L?BeaKo28G%8TohQFAl9e}!TkI*Tv!gcNde{hcTkw^ z?}X!S!s`OuR2OKYzm*VTH+iV9-lw?v_b@l_gAX6v4>{5QP)0=gUYKnpx;X(If?o@Z zyF*Jo6lPaCD6m#TZ1EE2x@Vdr&eYFKLD3k!Zx>?JSLiTkSN0@6A z?Q;=ob^T~7MQHhla*|?;@d9fb#16EL0T0k}a&Odw=7-MeFpenC>WtBuPTCfLvN>|ylBr)>K=-+f34U5L6iy@N0Fx5x(S zfqf)|%$P3QXtu!m8sgavD8CNvC#%Rq`|Yc2triuc5W&n&yJGzUXfgTnXW}@D>rRN)y{|LRbBQx71tDMEYArD???Y-| z3DMoenlv7Qz3pJ@JYaDRIheCbXP)N}up>Dq!17T)Y+Kty`TBWKh;jt7<84P_BYENI z6pHH69tNv6Pd=|kCFlA1Hkb(T}Qe+i}vJ6lkgIQ)vXrmt0jyx z&yg~eN8jLThxG-cr4i+Bfq=w(+mU!2JO_Cf#dH}%^A>$IrAC5{DkDoz1$Ck?KyU} zJe01}I06vCT*C_+a=4G4dX!j}GDuxvtialYVEqv4_|q6xG9sOJmAv+vQnkRuz^L80 ztmZDXxsQ5ZGA`S1vQ=NLWO(u}k|#gmK9%p-)$v{R%F_ZBDTZg=`?!te<0PIl8JvD; zs=)dX!TBJ`kL$Sqso7n-6V8oOmKMP1usa-i3Tu=C)N;la1gC4XWOUZiM{?t2tX!m; zmGI#jWoUto%7bRZ^E9{YMYReMl*TPFRAB8yP>#B+c@x_zxoviowlq=sS)e0f%4&SZ z-=*3lZV!p)Dg>v7mW@J|jFL{{h5M;maoy^^o%6{`&VmK(K5sQdv8ve=2GQJ%pmd#` zWuuHGqlF}?xJ6ZpdaIXZ8?^jNFoJfgXV^!vgR9?>Xl8T@%`6+;xE|4k9U=|;^gwkY z>8erb*77UC4gzPbK7+8r*$85}8!^AK>|G-T)(V6Nqn3?4fXYPNgwbyge^XKxEMd&( zXTs;y+0|<#md6m3T3I%_ia>Ud^g=jBmF;Yss$D&zj4YT!Tzj|8SiMEH2&P1i5b+b&}wsP0gO_Q9>51A>o+KX#ES+9`&SUSd8P^e=<>EZ6i<}7zTOo zL#Ra5q*)Z~v<@X>!6K4PE*%XILd`*1hBb^BN!@0lzFHnbp!y8Rd9Omp26(lRpqcUbtQ2E>krq;fg!4C9zN zfi4+P-W9x{#oi#+6w?x*X_iq!4I2}y9St*$3ml(?uE0vQ_W*8F))oAqz+Mab0MZbo zWmsnjgubI44Ks`$&g-m#xdN-o+^^opG=3$xLLkFh3|Cx38lo~D!|*s^3JbldVFkfs zK@(VKk&@76ZNR-k<5z+^m>a~(xrekvzFJt*3i74~!j6Uj=YUI2geV9J-PVM;O4(NM zhy6Lm0(la-QZUksAsF!^;c9MuwT0lXpeuwgkh=Wbm@HSfE7uAhanIUQiMjIzl(7&O z2|vXaSUUmi206=d8;}$3myC(>@dRaB!6y=)7z^gpL@UG{#qir01n{|mT3;<(0AM#6 zMSFU^QZV^#oB1QbuhF z@);#r!82aidN7sO6OAy1;rAe+h4mS zA$Fue``pI>bZ(x9tgluQTHc))Pety`G*T zwFbcKZjPe{fjUqWvLwZOQj}c>@w|i}T;{exM8# z^jcElV*%w>L9n*fJ%@PpstQAIH=u>Jh>u^GlVk&Oa)L}0MvkdLn53urmQLm|HAD&L%~hFKvsY;z*PX7z=MQ@ zGlbVL5^xD90b_;ka)2U>l#1TflGgAsrtUi>Ev85+{i?}LKy1|oax zM0hpu{?%;^yMz-YOJD`o?*N=;QXI4kD8Hq4)OR9D*;EkTM314%gv7JY$1ws5Aagrx z#QitXPia48Nz;+`f3SD%Urk?G6km0$kB&Nywo^M+>vWd2(@t%zbyhJ82!W7Vroh=X3AbKe706-*eB|Irn_` z;a&cyIl1?nRIQ~miPX&6n$nQF-4p1^^A|N2#Kx+B#-=BDx~8S>>7P&jcQ97aT;$K| z33%EchDsx~S$a}43ddt}ZaHuVRx4#|k#k5snXoZ;!if9#l)HbCclT?I*;uCb3^Reu zp)jE5#ptb$A$``J0eFmY684_wvENG}*AF0bt&X_I7gtLl z(OJx!4@fg+0M_+TtLXHF$#80Jv_;f`W9rB><-*5!e$I^$YQyRBxm>Fw?(suEBrr>caChEkNV@Gz*V;KHr1iOd zgI?K(>>BWU^0V};riAoCL#})ej{4J-Pqn(`bNMbsUwsDXvQP#GuH&x!IYYkO&erC} z6iRMi)IX4dIqTt(VE#@$wMiqR*^E2y|GZvX%w07*naRB|yv zU%e;46}T4?k_T!1>h#M-6xZ8YEys<_{6H)v$w;IOLf^J6dKDexv)0aq+gs^6532fK1j zIPa4*+93^tlveRfe)@)Zfwe$>JVLBPT(r#%S4~)vliQ(n^0jDj7i~(i3SA>^-JA4! z^cj%?YGJImLf&Tc!c!Bk~cn&FRo_(-uo_fK6G)>q5rSBfe|DBgml)#LoET0ErH@g?fY zH>|4ac@+Bdbs+1-Xf+^MdSRTmF=z$s%lT5Y!1`J|f8R19@fhqEaw*>rsrate#uuxr zV%1YGeDLt+Cu@AX0Q*PrXPW{uYjKP*c)cN>$qyv!t5vhb^Vg|?I1NZI$EVcowOSc} z|MYO>L0Fa4%TcKs>qV%q#-Hpc%+MXuI4BTL5DMpa1fSJ58)H)C_!zv|0|aZuSBE6VFwxhyR14 zFE3Zs(&XSR(s8U`QH%eU@Ft7!`v_9yn~i=VRbPD}J_H#iqb04Vd)-Pe$UD@Z;n$}@ z9lV;FRu8CH|3zWZ{jhTPqxjy>n17LPHo9C*uqFw{V99mVwN5}RZ zIEoL#k9FtLQ|zH{e(q-VpS=iDOQrKD)Cy~<_yA-KWB0Hg2)*nSTB)0RpEa*k7sa=Y zm7!7fvucNbU+iT~5BLzIj)>=Rtw@2jM*K`b3gYK)7U@bm2I0+y8m)pGYXgNUiQ=x@ z^K`UtJaHD9ns0F=_w=y zA>9XE0e^UoqS(HN;8gr3ZIM=3UrA>z4Y5_N5H%s&!v2CVcdzaBFSCDGmC*EIv_I4K z2>X$(uyRobvgwGSw=VHDZlyqh^@()SqKFH90M-5IL?_R>U6vQW(|KD|1Wj{{`E4I~ zKf|8Vyo4gV8^P&O=`;$o!dfmq_7ENomy=1?nQbvz64JLp#q?t^WVik3w=VSYq3lMJ z5$>)H;xELP;sn+P>69@%8m^IUb3MBI@4Rhu)k|~hw!s-gwa4l$I@i!bJ{Pq|%Z=dl zoOBxhCQV<>Ss|UWMnd3~p{8OR(N(YA;*wYI3#;szNrZcCUMJ4(bQh4QPDT7~%9c*! ziaEjr)&l8_F+3U`>5rwELeSoNx5w{N$urYP8L`-L?IQZ*!Ah?Re~^>Z*9=|(CtUkZVd;bh2@h@<2qUTYSsI~`C@o9 zpr)>y$vN|Zt#ilu+f?Wz4!hedjXTF7^08%;s7AD~!bgO&ID3^Sfi+8d)Ey;6-2f^3 zo+M|?5j!0qQ`-hq2l1*kLHuz z>e(&?J3KaSf=-KpkF1E)!fGHe`lE0b=PnT>uvSWsxu3Lw6<>tF$+FDC^(7fml~;mL zXrsi+Yyh9w6%f(a2!uY6&f-Uc1lB*Kzh@CXOK$)*u+qSfO@+1Am9`@)uT)|s9`(iG zhh5N)SVRk}PWsQ>zsS*7pGl9nAmIw%0;S61+)UYZUgecSg2W1@*%pZr@al&i5YLDY zkWNWwaiJK2wO%+=sf2z@1L(uHni6cDblJAxIk~-1#f(hsuS@jk1tk5gFtj)dA2?V8YL;M(Hdr7b37e z5YAI8;a3x=fwh@CNs(t&F)NL!fRT@5c1bMm_+}SqW6o{DYl8HJgd1e&t2rx#^W*~r z+dfbOi)(>pm4SQBB^56W4DPk*(VCk+inN6lSM&-eam5@F0&9VAnlcEUHS1bwx7o^X~3KbSxbEFU#H+G8-99IaHzLPMp; z8qbCntl=og49g9mvr{;S^HvKGSbr2w(jGvdRdX6x5vm1NZp4=QrOpgYl(*Rup%q)G zjYf_cR_bK{pLd0mxIlowdPg`%gs)aO=1h*=(A4Ps!II)tGpJI9inD!|1nDEH9oAWn z8P-hzozlnL*Ck$Gt$JTJMT8M|Py?%-TDv@URId6Wl__92zu#;}oc2>s=qP7Upd9cn zE_@;9>{SUDSWAV68Nt)`Cg##&EwKDnl&y^578NOMYzf*iisgr%Pnctd6$Q{K-TrZH z!Ufh}g)?+Pevs|Rz}(sU(6l&cMb*mJ;VT1R$0$~EC-is@aei(U%4bvhnEU66)>m)N zmrW31#GSLgXUydI6m-Rj-8JQ`erZGR8iT#(oYhkMDyrNTOG%?!5s7W{k_ zaY5dQqJlg{zy}J55RHHcN(GJicb!hB(`l=T;yLH8weMR0;H)ZSL_NFJYvN zH`Rf545^fvJny<`c{QQEgXYm?`?7mJw*4@Yw>etLuQpt)c1~;ff_TV0EywmV?#!8Gng3FU z&*gn=2E(2Yxu8C+QAvd)fp31xG5z=)C@h7bHkvJ&h62jbc zqp7Gwv#%l;Dal3$yJr{k{fs!4o^24GO7MBxVd)WW!R`=N!K;G!Y!d%0;ER2E`9|~5 zZHbJ?M!_AMmfb-kiR z*6nNN`x9j(7dnSuJJq%DMhqS)jL^Mo?K zKf$u=6n|L$6=?pVqCFQ_E3qvq4c?-rNy;Wi=%QYV#no;8%vdQ4;a`Xg`VE?Ri0}PI z2FX$GE|(s>Br(FmFxn^3gJJvX7R3j8{dBzAi3v} zi%#Sb?4jG6z1CODK7{7u61-=U3>mHE+hWmZF!hY+cDwN332EA(nWxeHhWJ_zX7PuO z9){-c!(|=|thLzo)P-(Nhe&G6Gjt*E^m%i6Cow2NA^b1W>=}AsknS(clic)xZ@)HS z6ZpBu0&6!k8#VAlu=aEKWd~ir>uxcZb|y|sO$h&wLVI)FYrEYXVH0##U2a! zk;ek-6KFQ@XR4G_c%`p`F5VqBmvq`RyIpvG8Qk7&!!f#_P|q=2e*(VdfIYkL6L0m^ zU$CvIQ1wtpaF;IJ1K{8(0QD~E<3FEP+)C>X5t>aM+PW7vX3p&-LjQwvWKJ| zgkMKRjV-%hVEX}&DQFGApO^cg`TMJf0_%M_sNGuVzmc9r7Uxa{Oy!w-8ZIil6gq9~ zCJZ!?@qZ|tg4Y3b909TOzKV`Qrr`v7A+&MKvFIj`LP^Zi_m9` z#it^(7ZvT1z*-4yM6Kw~c!|Ono5>=arSwvgC%quND)N#IxxmRdF7h8zu=)g@#z|=U z)_NqcHbb+3zCQ0b#deD;WZC7ho!kuIOfHMNUz!bb_#0p~<>-F+l)(+Bxnf(BnWUoW zqQYx7Su)Ky1KB&91B&bppaq$|_q@0HA~8W`?@#uS6Icon*{^R5R1>q}?@LYD@^43TY;E2BI$l2B5+qz;7FM?sPi zhZy1F{Q(1~`@l&ogl2Dv2LfvYG65lQ^ND3xLzp;471z>?q?3tpX#>Ftlsz)y5{*=} zA7kiFoI$^Y06nsGXQYpDM_(8|!w}X=sKVN8f{kQy{fLx-;0%r!8M~WsjEZ)Ow>Ico zh@dALdN9l#dW^eo7TkL7F|_GtnSxquzl~gSH(t6xa0>BHY}7)n?-(d&TF z?72V8eK+#wcc2>&!&6?a=g|W;GD&irRDs|etUM+RQn9{=fKea%O$6wf_#e40u(l$9 z{*U0c)2jlO!x%L2WXkuWB!S>8E|^$u5ObP|bBbG7ncyTsuR8hEZGE*0`Rn~T;DvjJ zc>--ztq>EFtIy9!4+u`H$0|d8_Wnm!JFcaep zC9EFx2p5l)t_rNLkUt&#Db^u^iI`Lctic%mMFm%p_kiC^LU}}lUm_qh4V%JQMf9Mk|kqyfA`IHLlVlPEjS-u2LW9Kka@WbdaZp5h_9fuLa6 zq~r6V;ohKz&Bz_XTx^pW!FRgDL=D19=_^5aX*9DhChQ=34>E>N=NLAF$B?<(?V7;a z3jEbquq~#O;0Q@HZl<06K>n?AzThRg0^}~UpNH!?f&*SBHigJ52tIX7U#&v681Ngz z1XqR*@k1f;J7&oN4_u%>yazKzf3QEUbqkh%NPC4sd8_?s_d+e-z$$Ax&}S2Oupd`Q_| z2tyD`<@TGsJX8}5m7c?9umza9o$lzX=qTWC&crsCHhhQUxpkdY!>zBbDc1|(Kqz~ZdLEz6R%`})fvJmH=8C{ti)=0zp{=DFKeDy(jPmQDP7|s1%Jf2bP|vNfdTEG` zdxRf{us1$K_k2EZMPPk_e7M2(w_EtZi)ZZRMe3=E2^GroLbxzTt+4!aG(=y(XLBA~ zqGkhAx6~DZwFCHzd$8RN|5ZtLHB0DJJLxtYJ~VzYWop+2ga}$pn8jUI$Fw zdv55fcai7Q7C_s|EdFTUAWe#(9)T4YQjQnGi6QE@ggnEr`ta+4*mEzCUt%s_;exllMFF$I;u(h3jUT7_pb5-N0;cXyE(ol*fxmYW z+u3U2eJztFKOA7zSDJq%gdL;IYdm?@dG*3`S&O}W=m9WwU%4Q#Rs(-8_Ug(m{LG)j z61JE}V8t{my9?pRx6GTLn^;&b#^3%p1Wn)!FmqcYYfnx9`^D)ccuy-~iCWAfuwwQq zw+jepB34*chgevigy(V(G=C|`z3lZ7wI}B(wkUwV^xz*?-Q9hXXO!6m3_K*BbV75R zp$wkn0QTh8o50jLzb$7c@YgOt+sRq@n01aNW}V_adixrc*98Zvf}6PG~#HhxfCKEFtS4@4-8$tS;byc-YAZ3&*AKR9=VXuNe3g@WyW( z7FZtun@I<>ndHJB7V}vmRugYl7*? zTgd=?z+$<4U0q9?6Y7-F1uV4EI#X2&3B~v;pWC7NdkoCnCWi&qcHnPqfVPqle7s`W zKQT<363)dbp$k}udqC?>eIyje-a%*bJ~V%Wz|6hltiJmFM%+(*1Z^azbc%5Zv$P|q zZ^kR13uwsuiPfJ1Ec4v)yBF9m2C8t0+ZgSrz*-AzBgxP<0)N*bfn`h17;8T0Pf<1( z@KAk{)uUMEx#RE4!M+=c+{XUgQGxXZ@RwpQdVYlNVm&0mYLqn_gu0c>1<3q=l+~xY zNEj|bC$a^aKIDbZOC1$hJ8(ZVDG%91D$qU5M>19>zMM1{{DZx7e~Rin z8)GNat4Wi_v}tBylIrfjBJ9GlT;*a|xmiS44M7nEgb0eduz+|2L=eQ-Am9azYoz~O zFEec?6OHaUi}`%t^FBYFU*GR@Ja)DdBCXE5s%U}t) zPZp5OBD#W2YZ$7%Ihu|jxZ8ShNB^$#-P481_~cON+o}4Cb-l+UIsc;n93Kh%`zvz1 zx9(#7)V0viWIS0o-Ca{_F>^wrCq@5Tq8j+l(19#R&yXJjBey<{0oEtnX9lXRe!0oD zi#P(&nR5SK>%&u^)}}IgKq?VE2Yz$Q^|CG)zY)gipMHTZ_iugA6=lWmsGD2jk$)s8E_mI(eRaXf!pGR7A*7? z-NB$uv801mBptw#O`Ck5b|i`?ezeKjqKV?f4$Fh@ClfV)V0tvrr6&l3=tam6xWH}p zLJQWHWZ@{Fo2X?83pE&1H2;w!)^mTCI(tGRKe{OijNI%wXnFBnYLZ-sRiqItpP}Q3 z9&`eC*`%!r3*3Sg+({M=dTaJ!4f8MAg_~g)V137hmsNq1{jrMt<}AyU|I>7aqK=8o zkX(erScy(~gC+B2^INdcvJs`Pm^mh4pY8+|jepX5?f+6kd?LbQQ0`RRF4_MdT~*Yv z;2sHVlW-UVQ8Ieq2Ek3{w_u?!CeW|D)}?`6p*Aj;Vig4gmPfj2;$aDB zTj>Q@v=_a=#ci|sEm*T;(P)J0)maJi)S(0TVDU>&6V_k2FI+;Gw&2di-y~t3&I=m;Iygua*+ z%LP@fPy$-|v=h2Uc$$mbCevH6(93)e!?o(Rf@!Ml)ie6RW=}inzvVATUXJwFm3q7D zy+d%CWKLq+DE%+7o($e?E^eC*Z^6nSFKM995SB}rranPWeayp7x^wcfPnhby@$!zW zq#(x%Bz_a&$-zLB+-$&2hOb>?_7<%DWTm2Csh?D^Oku&YMV@CJ^g!8yPo9>Fy<00h zrN^!|iBV|!K|=IW{C+NO={QHYh5NhpjL$+0STPyyHpxV-NJW7omO?U(N3tG8alzOIO@QS>{6Gd8on8nnIJ zgKoLARB-_9N!F$Pj0ah{d^CM!SX<5WHcs*4#f!Ii(c;D3EkTOAOK^9W;O@nOyIUzx zToSxMaRQX$g+kvvzxVoo%(>3&$j;8*o1HVGovcOFk8k4kdNPK!rK{7<)PD*T+8)ME z(m6q?H>qF!IZ7>O;oJijoPA_`WmfzXrLw9lAt<8A@+e4{>mcLRP#!1)?<*}< zVT>r%>Z1v}`#~0d#+wpu6lTwvPi%UO#oe{a-FXysfbtoXe7G zgH9oPYNW{Ab%4^dmPGS8Jc<5~$2u-~hmQ#cfX+ka!l_A?qb2jb=@4yDgUvys-`Kyb z&4fQ||zhG%3@=_C9szf1u@mYHhw6#mfne~pkF~;=E+v2Lik+Qp@{09fTPKJ5Rtmq{t zIU+m86BwIZA^!lMZRck2FKFe5JsF65y(l(zMC6v!tBv9LdNVDfrvP$fn12I*YBqaz z`E9kBHc~SZiHt2p+R~$fHzrd zS=AatrH;%^Y}0pbt@Lx99g@7Z+V1mC1ExzB3PN-XAE~5y!#AJQ8Y%rw{;&YZSQZRP zHphizb+o@c`?gQI2<9D~jNwYkhRyd)7Hn66GThQq>;!tx3~{5AMRR`r{BiBMsWP{} zw|&OP!0Lp;KI7uuIjrt|3DIYt<@=JJt@@c;lnvyfO^?WClfPtm)6GOCKz?5&xx==E z^pIUlLpyyrld3KHYWWPeHGSX^PxE)BVn@n7s?-MH1%6t))==W{QUNR%`B0nn zM+Yq-H!+FH!so>YfY}ZWGxZ;!y+t+mKz}w$xS$@!g>1%y<{0J;5#^^VCKjLj1^sbk zSaGv!&lG8-(+#KbKaL+5G-=9a=e*197mnEuLx0@gzoz8T#l29eYff}p zDs*?0=Z+9KMly_e5Q=lm=s;=9?Jh0tUa);HSIg&_)7E1gi%Id#W&ev5uUTw{ZDUbGjiVH@hOu&wf+qy?Z2xa|BnQ&w+BlM zH){H}fDs#_Q6{1=QACh?tmU(ITCyZ!4$KO>a{CmED*QK*Hz3Y~mHeX%an`6_`CNbO zvjJMCS)mMk&ZO@-mxTAo)BJk#L`qcjI2>Onhn3L0(wgSz(ye72gUc;!PtaW0Sl|)+ zPHLZw!;9DwUxMKkj&sK}KyWtKhJ2&<LV8R|mm0uT1iR_; z_yFc+xL!D|3&C#EpZHWh0oSOf8!ak^?#fE`Z*ftJ(mpTm1H57^kpgS7HX?6(%8}s2 zM#sv9U^{qv303hr8I8_>*?Lk&p`SL@MD;$wIgcuj1Hnm22+1H_ueSe@%2N zyh8?Ae+Be=kZ}cxME@-SN_fSnnO3GrN7yKhSK!~oT$+`Q^Lh^Z`8g588n@kFn*~K? zhIu!R{gGUIg3YGtR?Ct@bY9-i$8EDsGFX{F2wD%S${$h zUYBa(5Aa$-=iU(rJ5qk@9&h7D?=b{5iIUYA_MYfsJR+`PEW)SVgQ`FhgrJBHn(0%s z5Gf1r8eJ;glVDZ5D%xTcq*a!j0p&0;W_yK7S~h!0F&b~$G?zI4N1zd;ierFsQG%zz zx^-EQ+PurScGxvL9oYNip!ZJGL6buGsRj3<^B5plvWt4e-Qxo{H z0{NKa)!Sb(H^`TJ#cH}}1U(jTcFp|{QTUX`lA zeZKDC#}E_1;l!nJ-FtPuO_zugXeFCvM{>0FUB$uT5zgTxAM=Ncu`3r2JGv@FV2Fj% zx{(z+fi6b{#M$mPB%R~us117d*p*ej8ADVj%szjLX(>*m_4y=%laDB8cz^`gSgula zhknU{2#R}^GxB{W;~len5x3hbhE|yszrXU3LBE>vVw##bHre^9uQYacuDe%fYPLq; z!d#2#s8)jJ;%Q@r{hHaPYpQTmLZw4B2L*3}e*oXWP#X?x+8?*ZHfr{LX zicg3}+U$`ldWk-ZxUOqvQxS8C{&+wYcAc@}GDf8aLX2)sr(VPq@l=iniTa>wk+1D% z40Ecdf9LxBZ1eE_Nm%g0FIs;p(SC#@QwQgTr$b*wlqjOhBjbS?;@@7S z8t4XIy+-~$EQ74|TA<_=<@NUMk@ttuKrOg!$kEy0PVjxdPcfps!KUZt{K&m*^7v(l zg3TaKmioFdVaJl%C0Xzm;kQM>r~{`smD4WIVz(LaEyj=5Q6aXn4QH-b;8y*@-Tt== zc!+d9+9&-#YhuZ%lTUamMsKFp9DMe>B==k>JTl+-(~Z~=uFZDdu#b*3PoayC#K?8I zL|y~X4)Hg+dgH&Z`6J$qsFEP=v+UV%VAL+B=b@*gGivn5{e`#nD6q_eN~ycVF3^YM znLS#0E|%HqoQw<0UY^@2Y7t6LoN5Bm{N9wiXp~YrgBM?vbG~3F%zWR7nVTw zuRkARjqP>J(Y)^wVP(p zg5AuTI?sfK)HhFO$e;sxYrRIPv^`9i{ z)Ndez+L85awdj}tX z-p{*UdQiPhHKG%<#hH=AYM-6VN{&0Y3w#~9u(uvlN?DI2vdU3}s3;lnRIXTgMi3IW zX6D@4%QX&0l@Oq_hO4?LO4r*~$XLkLc2g25vsYv+F z=M}*tj%Sc`cHv?6U%JY6w}c12t7ZojzP4ySnFh;*SjnzUN=*MUJ=2>OYchgpTZbQW z9EE=C6(KI;o}%B{N&p5R##t zYS6*hD#CP{qSut46@PX~b<4_R`BAWV<8aq{#A)MMI}wE(@Mdc}H^bWMqrRolkqGpA92g<^_Sl1o3tdr!lj(l z#*qG%dd;_?QwdKVFKR^{6B9n{o0fmvlN!~{m2S_=ZCkDu*9I!pG1!}jg*!fm0(N1) zQ?Tv4DjnE7+S`4|hB$#Sm730NS^a*);xYal^^(zQB&*g2uQ14KPDa7e=iq01RSbAQZ;gAbv|A0bw?Z-|;sWXR zufw!u>X12<58{ICQCvo`Im*nnUk(_RW{iA9KT6;MG`KU)~+t}a&l=I*b?Omp>anAL|=!my&bemjg` zZgF*09?|tf9U>SJ?L{IFN~d0?yDn)#c2t_9wuB$#qHLCkzBUWTI)K5j3%p#P3ltymgaz9aFnZX`)U2!`?xsI{s13+G(v1 z!x7VKpZ*M^=Icd@R!f7`b>Wa)zn#JCppSs8)JZIjc|YoQyi3(gkZMqbGDXMD{-Ylr zOz?OjMe9f;$q4I^P(&{_#GH?w96r*1sMV%L+QA6vOo_01>5_wMH%&SklqS~ate81> zEGgR_AASFh3)Fw;kG;ij@=%#BtuE&^a#=GONncm^@{23G6MJgPJ(~0SPu+HXL~>x3 z2=ruiYj+DrKePXVXx<+a5EZ!OkmIw0|G1yr^bnBC5mmow``-p-TN+va^y!w+oETJF zZ04hY1HR#R0{v3#1L_5-hW95L+1^W1FX;Lycdz_9 zj3{((SbS*sxKsvz4I}G;ui_8F936kZ9VeC%YrC4;kABI$`Gl3s!5CWCiNMmhKLd}BkXl{c}`G1XH;Ce(Xq4=wxfd+NG;GLL}4KhE~ zYM77dVy;h^eO!(PM#NMq6Z396-_;JUW6=l*t|V_Lu%SX&AK1$Aw1?~8E?K(KD7TAX z?GR|)M@;TzHEqaMCO-C@T~}i`5_>JL+7xd7>mY0@@)~XLl4l$HI3x19he)VG-<$_i z{pbUa-|c2=Ae;3vesV~nL(>Zyjevl8FHOLTocgdsC3&!VwuopGnoo9_ssqKM$_8`V z6QRXiN&mU#w`u~^7qS^s&Mu-TQBYNwSXwlRm!}PFzx40cPj+ zY}Gaecqj7(l8%|xx9q*K?Mm4q-?5>J*>U~RR~1!ec*l25e=+9U0fxp5;;Ez2sd}=T zn;RKw5ZYH9J%3obarbFtzIA-P?k(|5k!J7yL8<^2tM8GdoHB|%bSiWv))(Yie9$gs_kDpKC;ZJ51Y>;myW}=Loi$T}hw~mfnqOs> ztekd#y*i_2*xys0ROxtC_2mSu&E!yWGet!@S~64ZfRPI{V8v#?%0I;L&OB{H+%+os zjZwp3R?qt(zx7~W)9lZMzJit)jI=zJtqcKcsy5-S|7!Yg#g3{I#Y2fY#LI>a(P-R7 zyrR27n*m+Y+QYD&3Z+~-Z+@#oM%q*{hE^ulU2)1;x0=x}`Mx!k($)2-`f~gLI%x&f zAQ*^%or$$e8j+wh9Kkybxoq}Jc^E=`Lsr%|XXBAKWh|N17W~d~Mspxbfgi9frC^Ly zxa)PA^@_wJsv?$i*pIi_X{bPXJlmjd2%%FNH&XX)f#Qp)g+t_`z zQe(uBz|Q!zRtiyI1_Ps_eMk6mtLlMH48sC|>dZ-TId6)euM!w3Ano&50~m$d4rdf2 zger@GH`<1JC~I<_G`}P9GeHzKbdYczj*X_HDyeste>6w*<#_;grF)e&Z_OM>nLYmb zETPyv2bB0AG5A03*k~HMc&^poHO? zf=i~=;IwzJ&z41u1DBp16N^rk*Q*oO7x zWY3=lm>lHnqzNbc$`pQIr&d_9TR*0qjV}!hs@AKdPc!sHGK#4VV`n%^&wgh3;56}9 zesg$(rR8H|lLkunS8GjSQFLaGS2Onsx>e>lo?Wb^OYqSz#F>@?`@DvMM(YC70Kq5D zzTGVVYMRQ3%zHaZS4#v|&?YPKej_rz@2G|rkvT+t!7f_j6|LLw;9c5oz&zGJyD2Xw zeZag+%%5-q`05O%y_wbq2BDnW`M|14K*8D-XTDXuA^Oo0C>VaPX=2Xy2j{g?6|Yh(dp>urM*bR(y@}&f=3M@Kbo$C&ILt5;VVf zF_u}?7;9$fzs6}tb6?h||zd{ppj^ZJd#p!vO7ccx}{rBoP5 z$}fmmU`S+0?2NwJBcYi9%XmsuR9s752YqvYv?_X%eh|uA1*qw+6&HhTZj!2>~CtV6l+_BFgf<7zv!kJ=FUjNmd!(HFB4s0g9#P z{PAmzPL0&)V1dSrMq3+1(Pm>YUXg@wZKmBak$F*tsiw^m0l8Jd5sY_@;s`F!)8*@h zs?f(8Sj0xu89mij9T5>KP-I{p%(naGE){FmvYA;YO-kjTb_vCE*E?hw<)KzxNwGBR zt&VSGJMEfPd4O8z%GC+B4=0&VQD|NKtiI{EMF1jlJ2OV=7dj;qnVnnHW{Sv?ZODF< z6QG?%Ynq_}r;^#V+bvjNsdUvHn1yn&X0A)tOjJ8Z&V$&BWwDwhY-t5b3Jbgc89^q+ zrMwOMQ37Gi0k~frrHRQ$7=4Pp^hq!xBuu}UTRjF2o0-cUrS~%K;t-dQ(EJ9`tMCV#50TpKk4k*h#=~ofXA=}Jv+OK~<$akHakFvq6tOdoK zaJKD|D|bAlhpfeGLaIo3;H}YGa*6B7<-Ctyn@U#=)@s#+5zKtCYe#pkOC}!07!kY5UuXmi{cvgN4MV< zh5QZpklKlj?qSNF{qdPW^EGNWVYeAgv<>sz_tNZ;C%WAu#;qrebo<<0fVpNh=}Atkt?x<}aezD<+ARHDd-N2SsU zRfm6S=*7L%N9Wj4AT!eu+6nMk>A?tONPjHlG{1+pkSuRgnbUwBY;x zbxko;a_A`g02{M>V27g)681DdMYEKCt?LgayU@!z9L@9MhLw%9dRiAZ?-zxGTPze zM8c~-%%f81#2*Cu$9`e_X#PQYd%PC$pb|iyNYI=yX^QPxST*d&Id|E(0aIaut~h{}?l>BQ&r!{f6L z>Jl4R$JTR1{7dvB``S1eGH`CIv#vUy+fV8?z- zC@)(Zj;7hNp!BhE!mliJ09EcdN2o()&s|hccbajEd109-+fANRx`pIlTA}kwto55 z-Ff+h^YZ+eX{6`s6Vy~}H6$|N(i5xz|>T(;ta6~oL9~CPyKH3pv z==(fp|Ac&H&}$!<54McG*Y)!e6)oaDV^pJps;N4DngB%MGcixq zMnB7u8Zjq7N}Y0qTm} zf>1JvGTl#?U$f;cGdL>SsLuTug9Dbv-t$+)jOdSJIthBExyLElXn_11g1p=iQ@gk` z@!DMH-Mlq&Hv*7??<=>;a8(}`ChA{054VMTWh#}t5%@q=FCKR(oxjCgSWQ23Vj`1| z=wk8`M|IPGXXKl{Hy5q8Upse+JGmqWR4Lr)a!>{0g{9;(7F6(-cMwW9t^-->yO@z- zHiz`$s+otM29caBRfS>S7s z5Y%ZI35(i{9ze>v?CMxOV|a@Dz0z!BR~~gVk~@Dlnv8mAm08F*c(kFvM50dcgZlxm zeNZpc(E5njKCVvX@(CB7W&*McEV>F{gWmg6wv9{g(W1?BxV`2y{LDF@n5czwfL{3K zRiWke0T{`V{5o}hkncEEIzV9ABGJtGjH1J*R)QJ!YlH9jnww0iPr;?e$WS2voSviG z>)i)Lpm;+}?uEBOfDrY3`bOvmCp3#h{L4Dv;$0O}ho>?r{BAChvW!Wane3K2pQ97+ z4uh29hKuY|@k4IDTqk#OBaA;IF!cX&0X|sT9Iqme%N=5d7K-FVw>N97&enXYT^ii9 zewEJEe9eQsYStY=iGM<;&3r{8plAqR;lyqlFmoX3nK8q5;Hg%N90L$L-j)XGRB2|r zI(|S?b|}-_JhRpac8N)#i-#y&^D@qhI~kFq0|t3g9zH#Z^IdUQ_uG9nTz$Q9fMcQ< z_|76WW1WxJPtwxz;39B(K}k}Fcls+RObIUf^47;rIa(yUU|sfOczct zogcmX=ZNf}l;(D4K!RWXB>Y`EjFF|@6rs*jjzZ)tMbw?QR&Vlk6EMuFtr7Frt?BQq@1c@Rc_lI!gw#kVhnBLI1b@81n8TeKN75SlTLcx z=%IKMyhvgRPVIe;V_8o)kUt;9<#Vt6U{7PY_~@h+dP{!jiOPR~*G{(l!4%)y``IZvxoni&hln0-{AVEVoG&*il^1@h7QunQ?AI~s#+CpCLxHQvb5)SG0l9`u zy__(#Pl7d|vH{IrJ(%~0rYtqG{h3LwRne**aGCx=3Ss`J10*6?%)f+2nDoEc+|x*| zSe3}fP7+aQpZ|pVdzHKt+c|8W_Xd><8q7;y$;{VsTtCZ8v}Ly^$2le{!5eXqVdLvo z`Kdq_&f}l*!Oh0wui{2 zd^ni7Z6lgS3(5iw$L|4?WqrK@Q<~~6R(K!<*Ps#g5$sQ4g;2@gEER~|bx%6w^66PP?KakeAHPuB z!8XP!^a$EXKi9e^g^DjqY0VZ=*VY~(iZ}oJm!`$mrt|nD#Q2$|UK-(3C;1*Z35X57 zgJGiY@0jjJ-VRzo#Sz%}DYmqFT6uBg%^NELZyI_p;H!4DbYVQE6fC$a!Undg1QUHv zc&g6pB^qeUHRf5`O)}rp+dMuxy<q?s<(cg!QVY5eIC#@H{7sav1C?yDg51Nt=ZO8GG zIJP4{Mw`H@t{f61JPdu-DyHrXCh2!Q2914SQ6P>mOHR_YLw?t^r)sRGYB*gQCdq+@ z__X0D;F~Us*90GkisIIN2s>CS7tBX*_9^W-B7_NgZlP-~`E3j!9rYjNc43$?TkJ`W zysgUq4aJ0mCYt=iF1YSKaYj)&0Dpz``wz;+Z{AVGCp5|@@~#iPsUcY^=_}cYD%ohx zonxZw$88ei$;9FWhe>QxTP<`39+UATJzzf0DobME857mDn-?5WK={$@ zTf4Yz!#g(V;{aFEbh2eANE^=)XN4jTn4a!C5{n$iq`aVzisN4N9oIjqwEuJlLDO^W ze5Mzfq-xDOQ{SGagtH;*8wXF6ulRUl%*e7IMG_Q>IRHDQ~PKp(>k$ zYrWSOkXrWSy-rQUH#?eg&8wB5>QF9)A&+86YNQmHhZ$EHDN326iRATE1{!h%ZzK<+ z^ruhOytvl7fj&XLp=`SQhXnAWtFvwPkMQ0(@qlg5J2&wmN*k^@YU}VH^6Ck6&AkVA z=$vnR^mOtUTNd`M|1>F?Y@+<&H27z86gG0=t2xs^HTtTU!9Zwz^TDoz#eYd02$Hik zF<3U9h+reHvaZPdqv*ALK-5>wEAzBl&tqR&_-h99xO4>-GO&L-zs7ARcdVWc3%&)2 zPx_bf{psQetK$j5OPY()VzV&12OOuM_@@N@sIdOQlhQ?NhR0-ZUvID6Hg+MG4r9L2 z4H^Xbt;Ni&QpzhcicVkDplfZJ=*}5mTIT~7SoM#byUiG5n!FAZnGr*>IC62Y zs4f#hw?yyvFQ_mLfvZvKoNqMEHTa?0PyDLP_R##MX>jPEaYEyZgUer)3TDSWAqZw( z6m6{l6hb~XY`43hu-LNPw=m#**elwLAqTU&dW2P2CtDd=j`;VGn2FnPHDtCit@C+D z`zdlH+lJ9%&p7uhIWF?*1>h&{b+F1XVzdeS`L9-hq9X-{BX2d|5BbB43xwle7y3uC zKx+KRae&-yP@i3@H5IU_5mdPP(#hnNfGPVTpyK?VlRC z|CeOj{?{VmXRMUhT814WS6Hq^He^Nq|AZ#L>e((D(h#Vu-6|v4Od4}BcYItJ@qe`($}x% zd+NSx)e>uO>xL|YTOe=yO0{0_7&pQy$efuvM!((;C^_~jO`XxM){&UuF|I`G&vEg0 zia&0MEL60|f_AFB?oHZxIUNi4Hj;|W*6Ibq)CBAWa@%0}ZPP#Dtjfr+dAIO2YnXSS z#fXD!(7ZVelaqaC9h}t-gOeG4FO#WC)LRC()sCmO&HID+e1Dl>Hx)6hbS&`i%M-yo zh+($X1QzV|KcM~hRIT5|hw{dR*evspFXY3{1>AG_WXN)wrfJ`fsvyG{_t)ovbK^X zT!fp#__t!7E}X3kcZ1bjT}P9?N`w|C3`YN@!?;!hz!d?g2qs7#&NeOM?^+XIbUate zP5A1T8AcqQ|JZweHL&-8CA1hwT3{&Oweb}+A||E)ZkqntDpiT($kW}ywV2F0!}zn$ zPj;Hep2k32lj@>pFyZ*L7JtXaurl1p#zzJJnHCd7aQXE9Q$y ziF4EHM`VrRT8W={>`2u2&xN zh#*) zSspFW1_G^i#nuHcldbDIwNS4|qp6t-@NrDPDE-P6g@;*$-gb5Kw;C)6G1XZgA~!E> z0;%-wTNS<61@ajnk6LO1E%iUNnsa9+7YrJ`*s$QdleMr-U?YOn(+nn-=Ujf&w;2`= zFD@<-#<$M0Pdwky^@H#31oQ;TmZ$&efWrR}5y9HJE~Xk@#*pBZzT=Zzp0H~J7Kr_! zyFcFoq@G=#Dke7wn4Q=3gWg=+0Jn)YF=672Qf-7coxg6uAOnB- zX~J24VeWV5GXAQuL*2q8OM`OjQZiqiM!o4_fLf311nZtl$D;feEH#X$S;dffdb=P;a%!y)D6{Ar zhaPY8vqm^W(f28wSphZaT+le3gLkQYu#I@LaKD4>havw+V<4)%oL3G^i3lb|OlC-! zO6#@-I@ssG8PwRxY#75YpZ=EHHBFu1#{!vC1oSHDHMfK2+$M}vc1PBFJN1=1egd7=?*KIo zDTUq<1&6;bTc1hoYR*o&pci4&yiT4Tdn90J3Bmx8#%lx>q#H{5b|#zeuX(l{7uRu3 zV`Sr>=4$FoKR3>T&y<+f43lApg%Go(4iq_kVpcov+^xwO#Q%Z)FHshuAnxv#u?o@|!}+w8RT`1Xk)1gSB`3 zUQ{&JNrI9|IrO~_h~TLRupzh<1nU(u{mJ+Hl(RKG-NwKt*E+fhu$*bV5xQzPve-@jhn&Ix_=!hb%QK=d#C<2TW^{Hk;Xgn>q(#34J&P*#v$j#h?}b;$9v=M_UYS6fc71Qz`5q(h%yMiHM6?C7_2jtZydx!~4*l)9%gy}1bk zP>tUwYYk~XY`>ky!aFHhC3jj{fpAvPhirpnlX{7)_piF4jbFXmUZtme-2z;gkgEQ+3dbi3#Dr%BK` zgY(C!&CA1g>FQu8!_s+Mt&1T|_sFph)FVdqvkkjXtLP6UPupCz(L5#ndsgl=c%IC< zTSxbM5+G^VLd z(@K>m63Z&%B}bwTm<}Rd(lu+B&T&{%5W^6m&#Jt223OSG4WJ6V`&7u6yqHm5qO7%B zi6G3|MH>()v)6-4>DpIoGV=TxzNI)O$i0&O7E|33m~{e_s}z%uSbC+|f9~7AMOq8G zoAXsN_ebU7J2QV|{*2r*b(U%ho$EC=?L#7r>fw5;qg<5S;RhVeX#< z%1v+@Kp~lyjALf1Yh_|@Rj>BBBI$0}s=%9B)3iaKCcJ*@%xF#{9dtADs`%;=4tY^2 z;4?3zH_y#nXR0fmOh?#s-;gh4$jLrT9VD(aB8_QDZX^HTW!qlzjqmyGD~2Whm_ zG6J1hfk}#wVEFo{^`-heXv zdfWTZuBd4U!nPVp`ZiKXBJl1FuZ0C0{`7hMaz0hVTP6-Z_b0T;+Au5Y!(V-QeX0#` zB72!u&0$CvKMqP(Ov3E*Z2Z%>am+YfdJ}&1C|1lh`*E7p+wO*h-!f@Hn=xzAN$hh` zw@t5wJx1T}zw{NJ_DW4Sr!l_TSQq@UxYc7IcAObclL7@$_(7ME7thACZAe(aZox^A=8Vuf=g0#vGecq2YAmr<0GxJ&=MJe zxp=V%r=Ko`qkK4VFHhJ*34=bsYs8ahvB1>kUWBQ+hTUx|MKfWY?BqXA0X2#HtmTi``EQ<@sv3`%z)3Qhc z$okBzU7?glCi^}9hHKG@U9NdFBwH=GZOGGRbJx?R5zgIp6i|FEcK@_FbF-~S1j7eI z-NBhaQ8%8D5evKqj5GwMMBJL3EL-H>IvgIWdJ+cK^Ofr4im3g|{c|~kSTqe2ssS^s zKpJMC_-AqX_4de{T~#o&rSFc^k#h3;W^CAnGYM2#WZp^pW2Ql_MJ}V$4CoEQT_b8= zDohYvYA=|9{|zmV+X^|hm|ggm_2)n!-pbnBYnlnjiBo4$$PBz~!~lDP(j<(PTl_^K z@z%2jy`NhAnZtByl2h>ulv{X@NOKdY8YA_Zxmbs4WzH)IBoPAPA!y$sW)+!^$&C%F zyBKy@0%&cpdq4TT;FFV!FVBj3H8PBAG3HP?5o8YCX$(4yM)EurfA6_?ObCV=f}vz! z=t2`43&~lo90idZMU`>M@M(IVg zu1mM@`WS=rfbu1bgT5;cqDFn;^u5Oq+T6pj2t+va3yJNBc3= z34);qO>FuKC=e0;u$x^wF!ZJgyN)(h*feR`u>uvb-}a2KLHs`zGSwN?Ay=5BE75g; zA?u_6Jv)3L(6$ln7mg2+0+7~;L*fPKk@ac(i*9xm!O#(e?p;l6S!=I9eLuTHgr0Nk zI*TNnx@dx?$29MHhM{DNiQA)Q^QvN3wrA>=+Xl4mLWP}Y_9|eMjXP$`!Kf-SUGpMe!BObmVsd$xshh10k zD&&yFJbrU3bL70~R2-tc{~1Ekoy{(HaiE+QP>xyt%=@Jj-}>eg;FeaOVo4K{X#dXO ze_ANgETu}7AAG-@{*R8=t_?uJZ`go4hg!WMgFt31s>LGp5h3zw#WQuvX--M0PxPZfg^y+AWK{*I26QgpABT^%d-*?hm6!> zwh1EK{WBv?SF9D3^grcJRYUb+rVVou2+jZ?@Uc#bscs3YKv^KlYlj646$9&0O`duH zNT(nMaHCu1^V11A0L1S<2SP-^0p%UtT7+{*BHWZ2sD@pKVcX7wn0a2DPJ?vFY_wkU z^vJm-Qyl^E$4m#zlc58qx=g0JYo)fp)1yD}q|q{U*Gf}*~o zl0E_@DvZ_wY{hE9>NcJdRJ( z&e+cjNKDgEA0)sGx|cjtD6<*#S!W1|x`3$F2X>O4?_yowsLO zSO2wScBBi-V?7gx^Qu^1SvJayE9w6_YHu9= z7a37ETw!8kk|x|}Cp3AAJ9&yUdFpr_E{FsB6lC-Giv-J&Zt}a+tB-0e>q;%Wa42mJ zt^jpAiwP@pE1_KK*xe>B)&G1w5szbHbjX&lM)W(k1xe z@zaIw8wjo}#F`C0L?W4!1$^@->)#TuF%4p@Wh1}47tO{fB@_rB>#Ac3eFV1I7Gk(j_Y_@XNj=BteqO!!;ce& z`AUwG2-tP}5n&rDlmP~yI3keR?B205)yXi`IWw_)Jx`4vlJ*M^>+HQOJC3Uwj$i3; z!+M$O&Y9{Qnd(^USe1Gai=Yz$FU7esC$pnle6qH2EwUZ{1+#-|>iQpWVIqH83hL$|{O$ zNI(X|i^BZea0Kzb_-WrQQ++E7hiCI21;jiCAK`$Ze9&UWUi<@Ejx6ANK2}Wo?r8yn zQxrng4XvYG_&3<$Xq~YQsF9TYvzq zqZvl~LP2x2x8|Izz+4%&84;KSwD6A?SC(*62=}Bz4shDR8>gPv9BMcX7J#du+-{{3 zGI6!`c8&dY=43X{4LF;Q*{`bGPWMhyW~l-=PLGymMq0xN_&KFbrKT(48GtAxUVS>t>=uC$@5yLLNo#?dWP39dqv)jdaA|3_fZE7;( z*z|xGZZ+S+z*oH9Cf#2>Gt-cWUmg6kxer>a0A)rB2r7koB(a!3cR#Y*uP83X9g0od zA{JQKZ_?{*>$@Q@xMFxU{6r7xYD4F})MA)Ck0B|&FrKo@1QD$jRqUOIq90mq1qMUu zJ?CVWs7~d!c)7HeH5{q)*Mp|eIzCh(s;VGQU(t98Y`E5K=M4J(Hyw($WUr?MLjd_R z2}ia5T6IIXYF1m(>h`NPiz2EcyiY2P)G<2&bUt+A!^~@N*S>Z?Avdqo~##pr@e8c6X=>_mS#y{=ED}jhSFdCfkyC&PVo@{Hf&B?CG6Tj#EUDx;jS!eCN&emD` zUiZx+y_Uy&PTR9G*oi!SnZ@8`lPn83{xsH5P9;l@+vWscJx5-vuZy;Q{?_F$OIfJE0{~mZeK|R&Jl<-k(n`!pJ!f!a&T7b9woRDS!NOCGJu1rd+@6cTWzr2 zRcnj>=_TrQ18XIZlBh|d?K`gVs*!gyVp^leGf?xWn6gtLi{?3ahq7Fp^ zELxZ;%i^XslPBnxGMVG-BJUCS2xYZiB=|k;Lif6W|KTWLy$koG>c3l8^jZyYgAp-F z1`UA;%Q5SQ$GoZO={H$8@@RN8G&ndsIJ`Wud8!0aPXsnJM&%=N5J7LySKS|ip=sXM zj*8sb8KDc7wR^p{nnwYjn--ibzdikHl@x6Zn<@o?)TExUCnsr(jw(f_nIxb_7H~oq zfEfX`g5_+MTShot?s}>Wz3~7ebR)mC$mgTXSjBFKT^oKe8c3mO6U2fVi~nsV1Qvt8pyOKQ;{J&rPnyw;mSv*zba+s`@D*on0hpw}cMr|c+_oJh59@Eb#NCP|D zM8Z6==6bfv?0MLqsL3rOdnX4bpVwp|tC)tYvrQH2DzbDrUc>zD%p`SFIC)hndBrz5 zjqhb;={i6Gu_k>#`8OLO|K3(;sS>7_nxZJr<#4X8;;{P#J&)O2r989+cZbSY<6}lM zj11s-GxuZx;zH8d?pTNaK?~iRX3=t?vxueuT);^>e`NnWEq8RgSsU8IeKYPUs~H7! zy$EY#{j+?ZmFrDW#RkVs&Q8dgF|1Hvu%2+<9Klh;yp>6>w@BF6H z3q6;f%qTN9z(5AECgNZ>x*6&)sSBcoc%+X+C#jmsAqw zj{e;z(3Z+*I~NBK5O?D}W`AtL-`p&5mE#pREoN|bCh(|le^EV6w=H4c#?ApRg-la> zM8nkdg5*c|Q4floXdROk|DBG@X7*w;#)X3RxG@*(_R^w9bH3U07jU1lJA}FVl3vBm zdu}*P$yvy7f&FNVUhYF0ku z&%)v4XR%O4ZuFQ5q$!17!E$k$lu<4Ua}qL7;0+&Ly0V3FINyT+#EJ1Z&{!p@bXaj zcYu{cB0lUKD=`z6!sj$nR6?v7GpQ7G*D)XLw1kOzp3Cr#oEHD^M~ImHa(+M>RSs;c zfu?R<1a-;3Pjv8gBlOWy8#J46Jz^hB&1&!(fzXx;O!PlMsm(5b6c)bJ?ANN6-_MFn zKHY$Vh3fc6OC0l+_5$VNuPhvZ*K=~r+wj&iHB}9=3ucWqXJ5a=;={NO$F_3s+#n0=#`km^Imp6uW!8svx5Zl6`k?Z5`N>q+m-}6 z%Ija%z^Nu2fH$XF_JuRczTTvU7iZw?Afx{AXcpXC>#+;AnDH0t1>+}2g4I11E>f2iuk=;C?P-3f!|DJ_+$Dz?%Ma} zIfrBa$xdf^gKfA$x_{TLy(R1t5jI(~t;_elFc>R@Ll75Q&TiCY41KIT{%x|=O32me z+qxv;4cb`LZ!WS1$TT626a49WzNz@$>#;j21z+mNpzDF^>PQjt&tadIBD7`>ECNLKVZX?Ahua63&?7=e%=<|v3Y0i$iaCT-I+HQby^ zMBfjr>$9WhjKD>jLPny98jeST+D$Vj(Q13+G>W?8GTNtFpUV{hn4tK7ckw!&i_oK~ z@tEf=L?OEfT^=a6Y0cYHj=g)s&c(c>K#*!$9@1uH3QEmD{Z4YiLXj@WxG~ZoD83jECb_h08 zVEM%x^$II+RtCATNGLxN2NYDZCi5C}~xqN~8Xa%vkO2g@p>zfcQHa}z{!1{vJp$@|rgz>1}e(bf6 zR}=eD1>&@1xb@b@!PTrPI%J_2qatJ19`6{`g|AR_pnHk(s6A=z)i?5yd;Ot6YRvsG z5{-dNFKRzdY@Um1n*~|HnsnrZrDilQ@klOP+oqOd2cW51rxWUa5>z8hz&i|4#aGWQ zQHVcGYkT=tri4usp#x4?2e-=vRx_II3mS~|7!e!Wg2TU2y%`IhS6_*B6tvNeC6YJOmPC1v# z*XM04o89n(K079@Ww(BfPSw&dHy?YyM)ptmMCO5J0x(Qm|^Z(EX)uEV=KThI9*i?B1+R*gNxjuUo&JWtr zHY+O0L#jBgEO3%MsBahE{$3RD;)qeSvvV05PIcI+z{$X^QsaPHVJMTB_tdjrP|e40 z(u4WC&<1w@o>}_mqWYO9d@R?09|ac)sc3jka}%`fhSAiHu|whTGn`bN&2cB=Y?M&V zk8xx1%b%3m{GooW@b)-;JI96W)%WU3kk+aM%-6UIICgCR6_V zm`H`hgnQB7{Y_qu?L;P7=*;U?CM0zOE+!NVPiuU|HO*ERDWNwXCRQ(5TIV3x?+7&2HP|s%3 z0P)%Kx>o!T5S?GkUiFH$q0{xnYRNhQ|8|-14=+!$7DSykz1<5D>*)LmSxGz}vzkdj z;dtJWW>z7tkKkT67f4=hBzFf11#cFKUfuW39WDot{?KY$Gu$>_gTY?6O4fvrp1iDf z-tEDMV7Rezj+LyCUd&8$Ww)Kpq=f(EPXvk+gfZl<}PjHVKfK&FIF- zY(|()K9OdBRNsjylbrD=owH_8o6HI{o4A44X%#KJ*xzb*okv;X>arx z>qD*mJ+k*v;-MHEj07 zBJ95`gT#3aReoE`5#XDOy7!9Ov;R5Fim8cKHf?O+vrchiXz}@bxl0^o8v&7_xYo&Q zIgHJ_gOj#}j*Y*uDl7C?z;GdpPtLHgcB@MP=7tp8hd|uT5H|@`6+o+^wF}nn!w!l1MfGhh`iVDPq!!gDD;M_3w18*7e5!YV$ zx|E;CdKuJQCHQbF^)b0ZHH*K$eLj6a_DgTYD3q9O%xPj&Evjjphvl zGz-n#5)}|rR;AZ9$}D?hmod&oYEKE&mVef}1uG&;#aDlgXLS-XSV@Moihm{7MO$<5jnp#Xj~p>3R&Q>vZRTm{#iNaBTHL`(M*K zrdG9C0F6f0Yv1<5H=Mn**sFf3K$-6^qrMXhdUL7ZXLxyz2~CDQCrtd(#uZgBnZsTF zK!>=%JZ7(q1ytG7X_i(suQ-VyckiClrQD!}PF8rRvw9&lo?o$R|9J)830?%?+ zJw8^D_*-WJcVq%E$${LWZP**oS>EJ}VaTniTL2%-{7UhK%?@c{o`=wMLZkL_b*Atc zaFDI@nYwYIqG*(!(SB9nzBVB_up(D#mbJ|dud}v}(|U^+LP;I_P>fZdfZWKMP6p38Ct zMJ)8^?o1D$tQA@LI=)(ZHtdEuSoki!V(ztKI69-d!0*Om1`}|Ri8#H$qHk>(X64v? zHFiROkX2d0=i_(N;}9Z3Ia^E71-5I^HShwwsg5t`cP{KU&uIVTR5m0wWagBFMU{7t zCEyi2+p@fPI!IOzRe+rgv#JoeG8pm`dLbCp^vX=gyKV|wEa2HBT zimlDof*107Bg>4rTIU4;q60XoP4B3`TAG_zKqfv6V!37&F-T;AN*mPOjtG%wKdYql zY~L*9Wdzr(3p>0RvZ8MRr*H64(6^eCTeiE0S~;1E4a1pysf7JwaoMJY!Mk^Si>cuh zTiMMAo2{+H46`tvW}~O{$md3V`;n?Ekr8^tBQFWVL{Y*G++kHV^m`XLmJ69n7WHe8 z9g)(#OBN#*F*1rsVe)#qQ2dLm;}20y`denYx*5L67yMcq<(MbD6oy#OmL&LY0(1fK z5$y#r`B(E;wbDhQ!Yq_}ZS8MxPNNib31g$U-d$JCXhY!5zXzRed>loQXXw!xK07E2 zg}|n`B=DU9IH?7UXU*`^H`O${)}{ znH?sSErsXjz%QPGtQ#n! z`!}X_>07==iMTu!R7@h$wMb}^0t%6 zGYu1MXcDV65G^StASEhq{hq{GQKFG2$|_DaJK^BOM*0g z?3o@TLPCD%^EAvC{~~hz`h%X(DtNfSXg6tmL_yRN^y^kIO@}1~uO*Td>gdrAD@f8V z^bx7Eji<1CqkHW(Q9iD-6yh#T#irbt&u-rS!G`+9N&w#o5+}P2Ir^7&wvwOfHi4v} z3Zc=X=yRI3)bA@*1>&iHBH1Yk?Y}g&jn_8oq8t~?O+)DbwiXq?A$}NYDd^5`81fNq zy6ra^uPKde)g3Y&0<%+?$X))SW^LHoruxI{XDKq{aT^$SoaGdSCw$3s`W>we=-TqQ zIyA(#I2avB<9+l~@1Gb^O2i-uY|d`T;@T+HN%bh0aU(%%j19L4SAmEQbZwbk9S|!c zjDiV0VaJ2ozJI?ia`&HaCDNcClD_zjH0#{KrJAY2Mc3>w-CF@+!{X{vsm!xBmZi1^ z2GV*eo579;E;840Tw0H_>oyZ0CvGN;C`(E)QCtSzy|PvHZ$Rr^L7!f0sKi5hVA%@u z-;ty_39%N3h3hfNhezy4O4yD$cgaYm!9r^w9zDwb3~GVx+`#c8HkmdDqL=i>5_u6~ zd@regHE3A?mM?os@>)W463god;cOZComotq7j}Q*s2kQUciD{ZoZcY2*?)Z6P_i?_ zU7wi)S~)%Pk-m_M=*~|qw=3Mz+X}mT%%vrWn(8ygc6@{rOLx_dS zm%~45{#GE}Fv>}pFb)L|#bL-7`8Tw&d)dX213!Q3*2TP@fV(+jbrdi1^1sZC%NR*j z`cpOM@|F#G`9-d&vguqz^oq_Ib{5|`d3Am{rf zP%gXq)>y6T>mqLA%agq{RkIG3vRZ`)VI$(&v*a|p#)9I=&_gB=lZqf~OpL7Uv^F`~ z6xMDokWJa1P%7US3E()dI7wxLTA?}hz7c))$nqxJ+Unz4m{Xe=em}NHx{wyv$!yY# zwrC7+QaA1v56*OSo;#(vEzK6*dMpzGk{E~xfXR9m-0Pr#mu@X)@@n- z?k2aEb!X0tdXEN!^8N z_rlOM*?!Gl(M6fKeBmp>gGcf-8}!OKyi4fj~~I-!(+QoxWj&;d4rcDR*jJO9V0FStwC@ zC~lk5MgA&dcJc;UD8GlD3CIa@=f38W#Jr3UmdRcpCrX3KtsdL@)bFMJA(SWGIO!ep zeSz%?6!j!sRj&wSMp4yzSu*s)RtB3{LThD z!=4;dhl3dV+9eCoOmC=Y3tA_TwhvTJNnjhw_hEQaOlg~nZ$qV(qzD6>mRbQe49N$v zQph>ffa)j1N|gviF3=!|q6E52tSaP6;f>}+Q|__8gXJwsL6vfP?rPY@v>=Ji;Dt6p zwK>5mx8F)csnDYP<47CUhScG2W(uZz)1w5}8)@%3c`E!+8u~n|w3EH8q%ydS81fyG zJdrIIw<(|~etKIcls2>rt;2uICvLk!d@(Bw*$L5Is8-l0s8rOd9>+P1p1vhPu0vt& zLQC5~!^UqJwACc~Z@oBXKBw6o%Znj$q?!pS=Mr<%=__raQp+w%`zCvSV51$;e+iTj zn_{GIg#QL~*oUi$uh=D7nrES0b5Q|{qe(yYs+CdI_o)kuta?&SB7NQ56!p6r+=(WIkWN;6;29*5jhcqDq%JCRi*_Eub8r&iHurmi8j8l5sXQ!rY{5t3;<33_+6Hme1Ck#&@gmV#S zR#HtY6%YDA(=@z_sN+|Tz^;BusDayilroQ%{^{IR@D@vNQKzlKeEJW2W>E{SOfzsK z{Ax(*3ciuOu7BhEM^>>tM_YH=J7$`Sw6a5HQDZh+HFT7!5ZTpw_X;6GnRoAU^g}Msh-Nbs5JxWQvds6OX^OG60flWeub_e#qB6Ql@ z3dFJUlr@K#OkjEwlXoI;RJC*|*vV!1e9yZ15SKpBfmob8aUR+!QH4EvZwJ|6f!qLz zOo)7V?UNu7zoneXLU4 zvC9~41co0D5rPMWMOuN5j1UbGJP-G+NRX2Z0-*@UKxOGA^3y|4Pp^9V+!#!FvSYX7#PUEtQFm_psIN}+Yx#0;AuYDn_d1Zh)loGB#3nL{xfbJMFJB&F zszo<5Jn5W0FYgXLQ~a&iP=V!m<8O_5TGGFRIP3ai)o|j1MpM<0M*_E|hKa>d>@-MI zJ-VTb#y#vbzQiNG-xN(MEc^C%w6PwE{|NW)(&Ue7q9)efWsz~7@X4Rjo-v*S6HXj5 zDc^l*J;Thh^aL2SN*vITct4>*HF4O2>DbvW4Ug0giq=5$9)ypxwXsQ)Ey&=yt6#Mv zh%Qew1EJ5XmwYl5?+UD2P|QI0LRbO+acUHw5M?`=duvPQALZy8CdzPam(&bW8aP3H zy%ta$c{aRN(QeW6EBz;KJg)&XZ8$AZ@&syc?J9 zo~Y#3?mPP&);`j9jk!R2n;u{RxY)2O^9P236ZiFC*5vuEsOtzBCTN`b5BT`7rq`wy z4)r@;GEx&x5N@@_JW}w5JhO>xbvXOe+s}7(OSXsA`jKm%_T+IgZ9S}=t`AF2;uW)5 zF&JE~5A2SS{(xJ!={?@`_GG|9MgA{gg>gf_YhjOn-zlFHh@|7=u<_C%1ET)jN9z40 z`tB%Phi~!$v1N{vjL!%yGH6=};-3}#=Pw6i!}WM#QoTjF_m@g~4q=VdA7ATCyPMKh{8*|+{uLWt*0*p! z)7Ab~eG+L7?Y@pXw|COJb&g>h`_@H=U$ee6C~42~tbff$XJqq04jxq(8%@*yDt4m( zf~WbYIj;@wj#`N7kRkv*ED&K9yD{cBvyg(MVTu3nY+*Dzfd(*ADvJX#yI*z;1|VbwOerdOcp)vnKi zWY7~~$6^<1!JJn7mZjx)v4 zh;os2&uY4r_NaN-8JWL@+Q!;(vw;=Fo-fKJ4TYu>v?>J+4`f60nY7}YqYD0dZ}pK0nXfrKywkiu?>HaO-eq!e|UA z@Oy3H>eb@tV)?+CEKx279E#hoQrlGN-dN2-!idv`a^sd@HSj%)r-(6Bg^F^JL5LsN zjnY$&qez0(z4kaoV~&hYSilM}Ip8a;alkvQGt_2HZ+Gu{9CEi_#Z9YKWtL!9D zd>rT91Tk8P(WVX5m(0e2*I%8XK5Kd`FuUkPrjrW3wV?n5Ri((|??ESE zgLP78jtehpP%KV7umjK4y63>FRbjbxL#BL4J#o+Cw>fMuM>dD#9~Vi+XDPhyQym0z zA|rMS1FqUbbwi|9Pa%~D{<=bvrI$RDYTSTA>?KLgE{YnkQ**@WAYiEOv+T)twVx+^ zqQHX`cgEcL0{qX1^eqwUD6=b+)JBog>w5A0PQPbFXWAMG$DSPu^3^lN4K2277)AI=?xoQOpk64yTLNo}6g#xP-|6^wI=s)jcu66sT9VCr$9lzw+nE{-DS86Vgj z8aispJ%QkmMRW4oqNy`2uiFnkor596QX`(cYQ=-S`@29UF1AF3%f1*|sm1dRuI`tZ zx#Dvb&O$L)G3sn7XO(fXv=+Hb$x&L6BU@W_q&62_l9%oWymGF^zz?U#E#9KP#*4;O zQp+aadJRI(sB*?G46pNywQNdMarDoJ48zh?(g&{m1x0ZPJv&bH5;YFO&d2A89OK~) zYNYFvPzzxR6fCyP7S|5%B++t8R9hF~`w*Cln2Te4jOB7T;E-Ym2=$-1|2+U)S2}WV zBbX%bz?(nXVU}_K2%>~^F#K82kUF|lGk`(VIr9J2^|;zkTZU7|Jxu|B*Xrxfnc9&z zgeb10AmaaXr)WXo$bf8&F1^*EBB%DR84##`tm;kNtm-_8KD3KA8dA)vx#bH-z>$?um6Blq{m)JQji(ttJEn zBQk}9vTY-C?9p4Bl!l^epp#*lzYWZwy~K$8Zxu;svcHGKzszkI$^S#3iGfa(3)nbsI4YL+C1A8qeG|6#gXr+|MAYksRZlYO#qL<( zymITcD4S~cs3223R--nH7qtX+qeON&DmPw=5j_G(~#{ zI53J;U#zlX;zImu9hT2TILba#_zaoSCrRhI?B6x>|G;jW@MCI&DNFRVz1@YoH&Z>X zV8U;z8gucSY2PuHZ~ism`1#w9JO=^>*enUutcdX?WVB7~8uJ^)-i8+DHhQsTR_l|O z?28|<8_)a;a}t=x;w)zum8zO*-mfnvlrwR4$Px;@MfmFtu#on`4cMahxNWQ3G+pPD z*1Ro=4vgrE<;sxpM43g75_tM9myL8WQxk#PN_q?*1%vbEiKB|Fu7KZLqMCGp+{ygT&Ts`*?M2li5?OS_$Q!kF# zfDZPl6RAP|o{}z=dzi_IQ+O2YBC!~M5z9Ry(}wc*MHAZ3^oiNgt9l^mNfIpN5!{_? zww*jMPqdM=eqYD*yWmjOCBA&PP=u9aJGs4D=+5 z&+`Qs48w!K<<%RVJyJn7G49WWmU40F--|kz6NTm%Y_mq*b@ftAh_T>>7HF8R>=CgCjuriHr4=1qEQ5<~ zvP0!@w!e(*0n3KR?bJvPAa{iwOOFXLK=1k25SAZ?%84(#v*@KO)M{#KSGuZ>uAJ+* z=uV|JitmD~o|#sl9oHUyWy|oB{z2yi^F3s{^ch}1fZH5?+$*~Q%_Ec7Xwegy9&kf;tzTS1|h{iRHX4^}CSM;=+QT@H;OksX z1IyZHTim~(O=)77cHWgLUA{R6L4REUU_miN;`Pul41u=i%7TmwGkTz#z&TxM(x;zH z!_vwzRrIQ>cK^aJIk9c@I*DnnV}btU!)b_DWy#>bh8pt-eyg5?xU8xRHu(dk6S?v? ztU|JS@kr8ytF>da`0IJp)Gv1XO}L_k7y=hSyN-ntSb323p{~XXu=+B++33saTsY1B zE7s!5Z&$0=sx-E|5pi|C#$`R`(h%ervrn?k~7zOz-WNN=hJ z=~1VuE@lez=)W=#=c_Ry@KWkIq*gEv*msESRy?GYGN?5(J#b;eG7_421cLm zm|A}|bMAK}uhhT22e{im35~mCMCrK09`~P$MF;EfkkXzi-;JUm)`qqUcO^W-yL7z; zl1Xp8t63(PR=(`(?MFY{%kz&mlHehfzM>S3;!nk})-YrG7ElK3CL!NBC4WN_%jB89 z>wb3+gZ`Kg1286Esh2`zZ_l>SwpPEStOQO%+;%4>;HI@gvf^US?+Lu8TRp)zE`F3?NwTXr0_KLSMA>jfh*RcFUwh9B~H+4W(tB$zbNWLUl4H9SE zV%*kblehNNuA21~9)t)(B!YFr+$@b(>;uqgc@c_6U>ThP?afz_uX!XYj!8EO;V7~4Tgu)?_Hq+)Cs{GDjB(me=rcfwOJ$=>zV3*t?N74 zn^HGtu!S+F90_j(;}!SSD(j@eo{hNyq_#nNIkR+8^wz&POy8(GZEu8&t0OSATK=BY z`C2U_*qcG_60I}B=x6uKc7sjnVc6H7%*2BXH{7?>f&@QG;JT0V8hhgu^1iD45P*$nXoq$+I3%EVMX(S%8@)RKM(Q|#8hMj=s4vwHc;-O zc!Ydejl;8p60J9+H=ut`Catpjf4}51!``$=8i24L4E8U^@LQ=+8A*J1V5JFoYp-}xR@5-3 zpOb02)BTdHMEryjav#Oh*(by8QHS!Luw=O%SKu5sBy z<1soC9m9D|=W~x+7b$E?f%uWdxbdNz^UD;fPjA!a?_D?L{m9_Ei^`%TzCI+8!FgJt zra{Q>OTHkBo=c8tLvS7={NmqZCg4J{AQ)?)lN>bbamnln4?1@ zS6;Pg@8fN4$1QJ^?BRc&=f?1L)QBzzXDx37FGk}s!KKSg70?ww0ICJlYL*F^+wM?YaFZp3|H1#!KhD|6c%! zBvm(~!P{g^$x_u|Y$uEMSX>T#7#rEwNCe$l-%F8OhIm*pY)N&ah>~a8(g%WLIU4z8 zUWi3$*&+M}kbU`|GcAD$*+7KCudJcIv6Z33^3I+d{ykxO0upQlg0U>-8sTgC+)1V@ z`b?|8CBE^b@=;Hu{;6$KDXySOmeMC7{f|zong&t47z7jhnf5z(ms>*6%V9f}vAm>g zilSg_Y#^@r%L^fqdI$b+M`5@Ul*l>i{?rYOUL;un-X){uL?}_YXMel3c!AGW-~=sV zhR`9*@cqh}P3n%ORdZmKSW6SGVBp`(ZDd2vH6n-m2XPGx^Cy**2B_`3GC$=u$t3H( zv4xNrT~QgMkuO6Oe>aDMBU5pW;VSc%!K;&|y{o|j6c59wfkcD$QlG@~6R982T(A?V zs`)gyPUUc!aQDdjqPdF7Wbv4t3pxG)-mOwz7Ji024k&G(zL( zQj@mA@1b>05-8VcVMN3JsmuvIMr{x7xu;Y^PJ4pCCASI{raIZn4wZSue_+%QV-03c zmIZ^c5V7M$ZUO*aaM~{B-u0l(uV;^68SF%EwF@IUF7R*vSqD)WEHBN=iATV7f+1ct z4?HkUhB=Z8rsmGQZ-bj(`z0f<>;|oBL;J~1>_sG?Hdu;d*3tk4U%&l;=J7PCj0!ur zI91@ED0#u8cF(p2a`y#yY3P7Iu<=3XH{fWouVB^FBgK>B5Od4^wQ}g$G2eh5xGE?~;3OQf1&H-;^ z&lcuOF^QM_i@68GleSy>5I_ACy}&^8{g}ObPKl%2-SRIOfz>u}wYDMGkWxRC?k)4v zMCl zitPfG2zX;B$M~2|#1%qt9w#`xvO+%Oyh(mri1MIH0n4BPZ$!@?l1r^jk3AEnu;ZTY zeJm#cgxJIL8S_5aU0TDOZfJfv@I*SiyMO6p8Y1M8#(7pB>a|92@XI{HBD$ZxK^U)& zM8$K!d;eQgAH^#c?$n2x4rS4L31EvM(35r3xgfxZM01TWj&gRhhEWqWDJURggPBP3xI{u zJJV!LSWcpuG+*(ufo+D!@ch#>YG5PWSDT(|xk^lNQuM zmf6>HeImTJ5EY}pbtCOb>!K=udJooO*|FD(0godS-m1w^m%;yu5K}T!xICvyf`q>A ziW(xkPw`*Kc?OgFDBlAXKu#|`32NGJX7>(}Pp{C5y~R@aub2T_ff zBXP=CYXGnWHuL<~5ax00v<}HZ);?#b!#*kED&~`asw=<;1Qn{5TuBS|H6Rw0o^!@?qebAIxkYUDJIfm8enIVCF4uLg3 zI6?qUmoz!dD=~D7!5cBBgDIbE4J?4=D!4&kK|joMNU6wxuKu??q@!0UESg9p*u~Uu zux-8}yG;2q5KFvSLuVE_-SfQ*K}NMAJ36G@udRGI|ys2FKX ze110}aEJVza~#G7|G^#cCFDXZ*y>uBsm3q{3b|o&8TlJVY*a$%Rz+E-#am9`JdC5% z!JLWHD%HB7R-f3X_X8|;9czVXqy5YwQh*BfZ79Ui*9($@sI7 z3@d&}@1{_79R*yOVOx(?a* zAD6anu+i&9n>a}*d~EbP7kFhPn|sN>fGit6n!JXfF3peqR zOR}TaJ(1;KHHALX*}?E&4+oH>{D10eo(m{Xi9Ep`)v($ibz81#@FLuJ41|LBuM+=> zD$wWrG5#cjt~`yG+6pzld5*)YQ7+(X56+7;LGtp9QP3D2{ynkW-U&6bxvv$I@%@zU zxX3>+Xes@aF)yg>M!uNvkmvug0MbZlkI?L}wDYv(jtZkxHnXJ7BXIHqVvq3AZSP;R z=*ckdw78E%0+^>PQYB)rx8@e_*iWn;E|`Mh^xpXF4I{JayLI?{3k$VMVt=_aP{zlD zFHE;qIT8peeq{3_+PeNWG(vT8_^v#1f(3mIt?74^3Q9f0ysH5OBUK(8+xw`R-CdN#gKCeG3k_$;w}+d;yGfua^|Pl|b`kCP}k z-K@J(F@3^ea{O(mRb5zo3gykcQy?>H#U9jggH6TijVAxs{PYqH>vIQ#{i%u0@=BuI z2_ma^m;b09gt`*!kAK~>r1b#y2>Z$=44zJ@j1c~@lu>;!AUEmzpn|T&JQe&z&g!*` z!><`ZO!PYKiQG{>mKnPluhIqTCyi#vq;C8l0M9@$zXrw6tSAvtq2I!G29e`tcn5k# zset}VSh(0RgJu0fH@9X3jw^2sY%?#L(nZNkU!^(+#m_-mji|s+ZzAJApX2;z7CMio zq3PS|oWHU@hGqhON@hiX;vhsWo6wYt(ixMpOTB~Q|6?RaR@@(DTY&Ef##wbJ|{WGVuotjYTY?onB25Zs)tbgI67N}1-wlc@S_|x=MFrP&CvY4=cvKL ze(>2GM~|fvj%rs*CphPgG{HHoE<*8R$PP)1_nmZW@PLEZesmruvHAPbQG;b|h9+YW zJ}a+sWF_Cc%Tv-6$IKL~kx;x2`Ip57`#9Yq408~BTX$M#h0V_TD{CV(8wK$1yqxAp z%R_vkGbT=SdUTsm@fr*@iwpHJx&v4w?{XOU!Nq9>(ENSvu)*4n9ZvVr!znY&k(U#6 z1+Ob0PIl}pbrTBt+k+-BM7Ij%9L$C@(TO~UP2jH_Hdu2$f~Mm!d}0oAB<7=bx{`O# z$itnO8Vbe#qT;Ut!@Qhs8QMuM8RWq;IS$R=2Xh=YSk@n*`G9{e$McNjz8hilj@0CvHY)8=!XMzx z)3*r~|3+1wS73}t!pb6=NkEjFsTbV5EjtZ0?(-&7~ zq4-yP-;fyJ(NVsYI6}fL{xuowpW;Oe95-0jYV450e=wA!O4|GR>RyS&AAFNOt=>Z6 z@sx}FfAAjTTZuN3a~=cmOm<-txZHVvWo^Tz1piduE0W4rNT@-BMkEULth?(`Q7SXG zrwG^LAqltmcfqe<6SyP=25ZAQXi7TZ-^s0FIj1_pSNYQR$yA|+9qKULjglOhkv%|o z#IT=)+gA9okl;hG)@@3G!Lrt3M^!(3eqJZZ&lW#l?b}lzQ-@4OzM2g8A~WKZ8P)}5 ze2d|)CLuQq|F;2~z^_u_udKP)q~Kqi$Y(iAagR`nIzuv*$n+dkpW#+aHVX~v5Mxkh zlaL$5|0e_A_FkD1gEjwMXi@_3qp)aB3Uy=>mcMDCT4a2Ypjr(#BA9DSjp?I=%TdhI zB*#D9b`ksajd$m##9&$PW5*Tz>r0*sy(B4`%cw_oG+_ zZZH1sEBMR2Yg6N|(Dw)l9x7&;IUZmf!BllitRVR!?P@r*eI*4oj5Bn1v-}+s3^D|t z481Z%25T|)9-*m&53D91Ns^8;YEtZxSV=O?dJ@Z3n5>o?%N=EmD{`0RXRH>U$~tTY zQ?)|~zegCs&(d+0BG^x9@ZT~&OO2x_=!q$PUt+PG({vU zldn-{Vz~gtQfFWNfI-SdVVPlQ9_nu}?G7RQ9w9++u?zz?>68a0(w<1xCUf|{`VZ+S zX%!v9`xp)7nK1?T-JA{_?4S0Z!;Ad+$O*!o5l&LJ?Dy0(}WFj-qmL9pBH)lM5q9J%1pG@?5 z7jsi;uvRR@W`|%1NRZ`8D--5CFF`Xee-@ouJ?t(H$6CdQ?GetEiP7xab`T8L83*4X zT%1yag?^7P6vK}&nj60ik1o6pRZqlAl_?rkOCkyJQ}SbWAL*mzJU?s%9l{IXZQ9iC z5W?RhWC*c*nja$HInIh$F(zNFLV3DRCQxgYB1#2`cU$0E-3w0(k@ZzKk!Zq5)xj6nqG!#z}(D@RZ!gU)`Y_P1g z;6X+(Xzc>elX>N&k~LzxK(b7Y-X|1*t|xAYReKld@=ViE+7 z5gcuCm8XHlFu0`$oW!L725ZYAaFPh7 zxqF`T6vykV`c-z=E&AolC{w$_hFHXQOMJHOVO^xZ@R0nJfKK!&?u!-x7%Xc!I7_Dp zB8})2R)}__WmDKK3TD!Cbt)EDYh-8CHNhFC?XZsW-1qh|l<5cHB(6vBS94aOI|71Z z?w-p$_3;UvdkW}nh3yCi%UbXeI89ju zvDW6}$=wOs0=dKI9vw3+I(U=>CDkqpOWz6Fbt0PeLeaoNKjQwu90-GDtw;ZvXZV+Y z%#*x16|^Ptv~d&u+^^;ZAHxH#3d(NUg(4b(WilB0w&;gqH)8lJYddpn1A~pBLU%>v6z@{;jKDI!CIUWBptJZp5Q8=63viue;)LhIg%qMqqK!jDDhRvxS0p&{c+ELwY|^3+rl-woFz%beEzT z`$(l48B9DoYr8BMpYRqAq7hge4Xj#p!}=bK!CHnMaDxmPTuM|Zuk)%}e!a^?&Da@n zH8XhF6A8I35?k_lmn)Zu=jRNBM$lPY17onP&%vn*GfV~QB5Gmvj`CJY_Y53Wi>3Ao z36F?-sYD~NI2u@)=u-(l#PL_w$LJwtDF>Pn*cO*9&lm@(=soy?dqv*Kft8S-8$_x9rbXquJ= z8W4GFK!gMv5wH>DDJq~wL_vY@h*_eMM$Pyb^WTlmiWwcFA~aaPb8CNM@o`txuHEO> zsUw`MK}6#x4ZPk0i{-Io_jNb5SaMKN6YIhROb&xXb{Isor zLtIzC2CCw;LaIk7!cYHnUWYOlD_UO6d!;FuMX4!scvSYhcbzAMRJS+7c` zi|}%QJxn^n+C^@1Ew1cwjwe5)2InQ8o_5B&GWEa<-0$PA9$-ZoGty~XC(2-L{)=$B z5)s?SCrOfdovfI*JdQgts1NA8M2zRVH0?a!lf!nMMD>pZMysTMLs-69l)*eBiF@0{E-Rcd*b5?O&v7pL24bnJGJsE$YM!iY$xanlN62Fv@ z>3;MVn>#LUc}`;Lu-cxb!Z$TtZqBtU=-?ISlDO_ca9S>%#`mT9E9*1ysfYMBJ)5G+ zxl|~fbaU5pJmrxD^*&30@jQ>K6K#w=^N0G)n}S$&*DRjL55yTPYrAyL4k60##7_?$Kp*~y5T-Bsdy+xD;>b>*m$u|HV+;OpyKL>esXEAbh~SpCzDs%p;& zTto|}wG;k&j1|#otc8C78P~(BU(rzlk0t8^q2ou8+A5yMFJ<~G>l5+JF}ARkcA(0- z4L)XJ@742$hsg9EREx9_R0J9|iylr7T!jY{_JMGk@$*Rje&^4G8Z7G{(wR$P99b8! zg!Br%E0%OGaL{ZOjEvfdV-gN$pe z39!NI9dsp~)eB#bAo0$)PQ1T((e}+GYVQ0Gxl{Cr9$^t)$0%C)Ylz+xYp^zo|74xn zfJnj?R%xfUAa-L!LqiA z&qBr=pgq8FDhq(${dFL_Pn3%PH7E-57(`7V$(%U4lhfg_X}p z#8%b@7H2RHFR3NE59{~f8T4IMC-u8SI{tihSHFiQzQ2ltJp=Dyta!Am#WVS(WPfG- zS$--)GI1A7RL}Ao=HC6<8=vB_0y>ZN{|BBybyrV8hXIB>0OR}=Gc`EA8e50=FA({jFg5^{3T_Hcft+6c5Q}!@;mA_f+@3Q@s z^`87(gw+2@n66%E;OlCY_RVLYt)`$s%~k2RSAF=ibfA|X<8<0t_BqHm0{Ommt8jz$ z#wzg?GM0_n{b{fwKW#wwEUwfJ`7Cth2VH%!u(zl)S+n3-C^O+w1ntLdS}}uH`AbGu zy&>FSSs#n%a3AB%ar-!|$~}DsNNdgs?UBz3^I)LWo$l)9Xr)Kv|7;8v8xZJmT9|_j zUU$krGx$`xzp~zvpN`#(bWEb%YHKv%5xblL?UK*`#he$Mb(gs+EK1c?w9m%@6C|LR z_N+rk5`)-#@~K=e-eA4*k$4iDAS(qTG6abxfy4+xrz&) zDUa1i&kYxiaNK?x?E?^Ei{w-Jg?xWyZCojy#zD%^2km!ra;*spTY5)(<(!dN9vC@Q|i{a&2jX68Vs?Uc{u=L~;ktp*4JPsOb;iK7FxXN7i;9BuAb6!r-rS3~{rqyv^^3c!0>wPz;7Bs+DJQbd}9{l;x-2)vN%Ie}H z+n6#>|BlDLk3w!cfXo<_!6J;g@24zmYUtqAevdKAYq#sl(Is|UZDj*vGd14PK(M_i zQZN##y^oTt`}nVIPk-=N$%FreMhYTD?ZLpPw`OK+psY>50WK}#gXUB@@PYRml+(k6 zY58Q5M%*9Zb3lSdD8*j@6koqN+S{Ugk`#(3(6z&y8ov$Xe}Y2pEdZIzSpEtz=3a*> z|BFEN9X3aOLuuMg6^h5PFJw-Iw*u$%?qb-jlTW7SPcVaJZ3CoeA0 zZPI?KP&|rD&F0j1KX3>mWeW2J0Kn!Nn!mDQ0IXJH6yO|CfhWxoV7pKkVks1lpt9GX z^3DSWU=+jd2>_dK;tbY`cL20v4!L(W0wv(MK@yz4OM9w9@ep}C4Jz)l!~;akJ?--V zHs4u+Gg#I#0Iy>h4Y&o=fcV`8iEx6hYfvbDg*U;V(jFl`NQt?jWfOKazs>Vk*2a|p zVvk|cbOFfJtW+rOBlfmQb)A(93;}1lB@AG5)moszvOWeddkvGP&BUKs zm*Y%Q;@x_gP@!-#`b?_oxN4%s<=ikB1JLdgql2HX+kwFZ?_ngTVf`8o# zHCV4L2ar31$<>4dL@lUnFiMc^puS9~a4kGOv#L4iCt?%^Id?b-+ijM=1~pjLR{(b7 zITHn8;%T;X)GSH1Tl7g`g-ekbF|3$-kS_NohTnsPpQC@J`YY?7gmk^ak%KEpRX%K( zC^vU#r&YKS^{s}L@@-@o4si%RMd0%TtiiH20O*b7ObKOW5cMD>WSA@$|De5A;XVvi z8CJ+);|C;a?Z=dsaYr(M+ zaS5Eoj0EUg74ZU#xrXp(Y#|(4&?~IH*+^MP9uz0gWjn0y8gw8{+#SEWm5hu;0cVCg z;|10hw!iY$BFaCgg|&w%(b=QoB-$NMwbE;lkK`hM+l?0a0 zf}{aDBS6|j_i41*Lo9=MWY@{d+{iU%EN+81eoP>ACEZ^!CN+>+So_0FZ8$4Wrd`Ql ztG@=>7$_B(xM|E-gh6#GfoNc@z#FVh%dGm(EUrS8I$xkrhjIc|f(?QpZu-?UUOkAZ;XcgV3%?^|(Z}96Bwn>XaG%W2-boQFLW4| zUzILVuOl|E!5|W8O%n4py&f74(zxcvAc4`P68sfoQiJ~k==4H|Vfp?kClb%2R*VhO z5WXWaSwqFpc#uY5xl;&Aw~8=Wj7bf_M$qxyLly0BWjd_(qgIa%ve4ZrGgq;T+MkdF z5z)X}CBt7aCN=oQB$e1jRf*#=RlDf2Rb+!C6z9pzRP49uO%lsLA}IY#h{0k^Y6v_7 z9boD(EI;*@Ox<=blC3Bkq#!w8Xqwhhw=a-JV7YUM->{awCB$HPUm=b#X-clkp-Ol4 z0in{}Y1f1XA?SW4G)WWKp(+`6!7|fWFU4PZi`F3sCoLq7^i!3hzfY)m7qwbtHb{Wf z>p|Ct{RrwOt=k?%P&$8+7=z_)Krnutq!okM5#kTZgvz)5O=u8+@Nud6nSy<~8bH0Q z7(j5kO^(0v)+|I&-b*^g53ve#r$^?&AS<%b+I6W<-L#K z{2J*PV~1h+{tK}Z9*Ns-LIWAC5wXeHgAEF51eRm0w)k9Sclxq>O~;jDObl!9$1|=Fi}w| zH!mx>4Y%kdPsS$VMm8<*@{ z647@Uq^=NVuo%Ne{Snk3Zev_Azm_gn%UxZ!RciwcPum2iWYYz1U{GKEkro7}a)yku zhK>3sQL=HDs~VRDtGP?xVQ<|HETrWLPDt#A=P8^*F`dsKb-gry=cXvY?z-uuM3 zx)GP`u-tBY>uvy{dZ*}gyaJ94>VmL{p?i{sjIxG}`d_1j;|^HU&x@Ayy~S3w4HOjS zicZFSaA=;RnEn@o)NS(omA9C2YZ7Hi&26r71fGZ%b+;$e3bz5Fd6Tj;aVK{`gMSyr z^dW}kEnFkeU_pkB`d3gVntVx^dP}yhm)gJv0{|7{vh#58G&eSxtic(V7_7c0(O-FM zA!VN>H(6k1&uo{i?4kVAR=y2$T<>yHWM^R`_#4zej-q-rmBH#(kp|0K#bEy-OF!;` z<>UTA+1l=EZ8@P~PNTk3cnX#@fTOdE#r0zbtE*)CEAMRv{Xv%Gj7G`wo+n)1Bk`aW zal>3i@<0_IhL!xLrQrc^?-?j4~9Yu-l;{#ow|!8=T+@Ibo2yL0tc#|?86{YRu{ zUm3Z-CZsvzq~ zutUDmyV?s@(+zV6k17=;T^ITXlMAd1!m<$tt@9TMHdx+9Mi2r$u=0(*Bn%%>AoijB zu$6VgTxnmWC`h?Fwkp=L*nR=w^-anC%3Gbph(b1Od_X>0@2eXX$h}KcSY#C;F-xv?i?0C; z4@UPl5MH;-_E+AgjFr!Rn6(26y_0YXBNsJjzAG)Z`fhl=C_Jbl)k>bCqZEVHpHawP zJb}f+4VL$3$O(rn%yCcHvR~h)LiXKoi%;vH9eLJQ&W_Uu9T z5{Uq9O3Y=pq70<#Q2wI0jU6?-CInmabYxl6VRoQsT}ylO-<)Fc?Zn;+<q0mt0c(9Vs z(O&;TW{mnD&r@Nryf>_)GE2yzSAvsz>VO-!p;(4jf?WwkX*CIdipu-Syh34ig${q^ zZTf`r;YS-VocSA=m&EB=$Wlo%}UZIg++e-g z0K@Fy#&^1MsV$Qpv70o?Lysubex=7>c?;%KqJn!9R8mdXn9Os!szORu%&dT677{6= zOjjm7!~3gh+|v6=3blV)pvYi(UsA%-jQhWN3||;xox19RyZA6@cEB*R2%gPVmPVEM zZ%cnCjq{=c3bk))@>kw+ObhEOPG=tS9oCT3RvQY<5g29?723X1Tsz-iwc<#hpin!1 zkt&1bZKMPyirX-OAL#D;*^Sz&gB$KQQ(%}WjC83>pqgxc)QV`Nk79l*_)?d@@|Lfo zMCLJ0YC8Ed!V7BE6^N8Q1!fEkGxB|sU#2d7_BZ3hcAD3?$IMDzw_KUQ^0rYz6BxuD z`xpEgQIJqqB3xdMO~o?&VWjTp)0aErC-{Nu!Lhy%!|g_G{>odOM2QV=R0C)B+b^SG zR9}^_saS?T{5@E#F>y)->`pJ_HQg~2X7n|%Ja0SZNTZ%dSS9qE;A)#DcR9P-k_B5DPF#L8DD16)gpMHJ0fZ*lu zct3+7cY{WM<*ivriBEDnuSyRH5S{*9l?B5^@~h1*7=9aKIq5pHWv_%?Qx|yNxCXOV zd*K?D2Fu%mIsP|!vNN73Kz8a6>8u$pFDGi2!SL%5jrS={l|vHzRSfvx^g4#!?K=IH zw;0pH@;i9vze_^hxN%Ww*>JgWo7rIal}O!@t2R$W>`EWw5zkr4rnQ0PdGBFj)E(hv zK&u4h=`Yb*Ib6w(WU~&2mm`=qsy9hQEI>HJBfhBx!|oQX{>uB5GxaBfmjdZGBxp~! z-s0i*+gL2a%Md7R)SDrtM&SgpbGKF35U46O4tA}*O)#`V?@ckZ@1 z2*dxiSDlK}qg2F5lW-;Qi7%(N=xt!3USXXA>Q9e|8q%ClTtZxDv30Qwzhtj=wQ0_c z12X2BWC5xF(HdCx3TtN33rvGz5dx%e^RrnjgW0Q>AaP$r7>S?myE*hO)$FfGEvymX zJNLd85fW5Tqq>l|A+uNpvseG?ubM@~v4OWD$3-|#-*h*yNVBkr@7&#>j33dehn!g~ zgW+d;RamJ!B`UK;1Ty&ukbBMxcjXN%R11sv&fR6ms3);b<>kcHrUlJb7|dSD@>l*p zfZUgIUbyR>fdy<~5iiSyJj3#1&z$;_VqGl5G=jzL>XTte$TF#a63M^I;di@se+Ak| z$b9GC_f&=wMF-Uv6_;pDHG82Q$!4#dYs-`o%#l1G`Mn%|t$~GVVG-ZCyGkJ|S2F9Y zuDFtTrdbTl2)B+}7PwnNHg$%HZ%aWh+^vB%-NH)Z#4CfSM#rVpmfcoaoa@WTHk+Xp zvG`ug0Oxw8tm&L2vVWDsZ;~~zrmz%rPgP3Hh=)=xN1j`4nL<-mw^|`O}z`@;hyP6OsO( zKn<+b=B}o(9h4NvYpVVKX79|unm)5Ier#QEX{Xgr>wfI<;AyLl({X8&oUmmhL_!F} zEYt)Um4X;RHf0e(ML`r)ECNMYtOXlTN1QVM-H6f_l_kqJ%X4`?KXJ%!?|t8UpYMC` zdvBJMD07?f!qE!`9oY_6m*$jsulvfh0e zV6?fp*Jnw)EXJ%1B+=#|mDMa8R|0)aLiSKj@riLvt_;SRKdADs7)v<4c2>6k$?;Ax zcI}3&s5=iddTr%KDyu&@2y`-hkgn;JoXZXeBhDQBE{@O@@kXUL;bC?^hIV>6(+l$o+9MI@45JH*{RhYmT{@Tr547O(&2Ncq1&lyTe2A)Q4!d>$nGUi) zoGMMu{kpn&g7M~U<2v)1DU_5O^aawmtKVYmtQ_+WV;a{0w8T4hQB}=lCzAK;gFGIm zN91^@Y7V@8mmjQo6ecn#Hl5&pem4;=$a_^{);RPaHT&5^P4yPZdy!I9m_3#21T{`7 zKEs&vE-B7@4b=($<&}r;WZ%PYlw;u*%&uk`w}968(`0I@x7mYqL_iygPYH@c=|>rL z-shajNQr`suC|Q3_n1|%}JxSrn#>g`-4YgU+DtH)6 ze&XJp7po*Q`#@)QLw&bxqMmyH3hNtQ^G2PV5lOzPlf^0vTw?|Js1OT{&r`*HJO5YV zuaXR1eI3&ZNG-6`U#*~?dY|=BpPMefS1&|Grt(vaKnvn$st_XPx}5BJwQyvYHEq)aYKBpy zMgD?XYF@TM9hC>5N9Cp{ht^I( zQ_w8RX|=E+))F+Bim7E1@YBFB$kgEC1oWaTUV}QN9xCgxWLQ)2 zEXyNCqNQ#v2My^|G>L@H72p%trD&D)6gC|-U|fZ=!}rut3$l4Tk|oPQJDR8_g-uj3 zF%~U-%O7y*scRDC)68Mv^VcOwv&pi$CV={R2KCNh?H1~&g*gm$WX!0(OPK3Yce002 z5S+F+*c~hWadzD7=3Wfqi@+t!@cpQk=z?12gH%zAur3M7milw3ABVpSb6(?&SwS&z z`y}T<$5UP1F^_Q<2E+9VVWz*2T5wke)jDzII;yC}_!#QYbfX@cj>p2>*9gaq1c{sX zSn<2NqPhx_^EJYZ-;7$|o`%)w8OX4P7K=lWH1c+tMwwhWgbeasF9PXY7m?#&xD}V>lAH`bfBo4_5nnPHo1x^yC3=4E>#&$-l$SAYt zv+O;Tyr9qO=dOv2!D4|MV<3eI!WglWx+!Rq_cBQstNV&u0^OR{&Uh7Zwy>|uL6H>% zI!9LzTiiyBUE=hn-drXKW5nKM>Zah?1a^>slZ0d05~H4>iXlsZ`^^TsE1ME(k-Jid z)t|zB5;;{bC2o)G30#YSB?#63plS+%6<;$+7%R?*d^$GH(Yi{d3oQn=d!L8md^7uq zDula2;ttURcjZG%5PrRaswosc13OE=NkY{NjYRL3-N(4480T9r)lgFXMf2#zQtk@n zzVSpVc+DiRNk+jI`=8WIp|O=o!kE!7G6-rfGIA;UO*?3HWKmnCkDCH+?gk~9(u>?F zUBD(mOAsEQVhWLuu)2*xCka(9nX%B2!QiDZW1iY^?Q+#tnx`&%152(HCc`9iw{!yA z1T8_x9;4#BjRMak6gl_#H5I2AzmzAp-Fko7Rb}N3bhYQw_R8b#7V3MDpV@%DAY_lx zFjxiFZB+dN_&{B+6dD%UohWJvL$m9tW?5*fVuvljClgVkPH0oxCge2oB-mmnt)gBE zo$tV`Y(#d#=ZrG_oYuk^7CovOEVbi$xzZ~2smnabd#fmNLFn!Qp75+vxzU2b5vrvy zSp5x{nTL@*U60f`zwC$=?fmjHONmch7w&9diRBq<_@caZgqB~a^@Yf0830@DuU1nn zg~JB4V>N|*ssd7n{FVn5lixotGj$32wmWva2?pFT%h?|sQsNs+J~?xv&%`hb-h<@&yw2FA98(^^A)jTff-Zy54@ z-pVXRI)$WWRhIkm4LACyFEsX@IL0+jxGdCTxjrVV2--Af;Cl6Jphj9=ts2zL*e<iUnnXVWf4*2ePz21?gR~U7#c%4|%&irMZ`QON^A1izV z4-HpL&#lv~o=Ion)d^OtCpc3rf;|j&sb_8t+Jdu1L!^AP7R~0h*#0jddBEHyUT6>! zM>0zUyBEz1Y~%cjw%}{GP$5OimvG1IDE29v7VH7lz2_O@2#H&I@Rnrn(uQrEMz{q( zNPQGBt9GDS-3Z=v>4sz5_fRO>E=1;RcHC*hPI5IY;0Q+I{SUmUc<9 z7gYa#nt_gx*i+yV?O2|qVVh?dZpAlI9Vx(y&*2Pz5&NWN_(VIxYBn7uBeF}O-yTVi(J0cMh+k0`dR^|2eonoT!%V z4~>nCd4$9YXR&O5l6L~!KzHGmd?kkvD#jtaEEIa3PpNQ^s4l5u*drt+*CRHK@b9%E za0?CM8E7YU(J~%MsBS`^eD_QzTw!@j8Tkl_K0_ykyAoX;xP?yRB`i3Ea9NKeRIC4s z?iLGMguBJ`DaJlRqK!xTr<%SU-9%6D7M()~6=f^l4uB8e^;+SMQQgVGb%aC};mxmR z%0Z5z+o%<9(GO4)Daw}Zco!t_Q(2}o(tTrfJ0l<=QM?DQlf=gx8@#eTa&Pb?)f1sb2A1yn9qXu45b| zBpNjI%J&~ucq;+Uo@IqQ>)dCqM;`F-B|cg!`??dNIMRE!zorDEjS~DnWRd_M`#NSJo^yYBzz6>bb$X8muXK;G zD-seMTD%%OqXK`7UM=7;x!6ycg?P^WC4T%O^bKopOVh@wql5&3oHHs6N5&V4#5_;px#MTKR? zyVBVn33;c_SDttkX5kl*uK=&e;R*L8WgXy(XfMaF#1r4BFikTw$PP)!+cVIp!znWF z<7?IH1bpzE;l8Bj-1i~w)#u>XVp)R@-!v|s#3JM^Nmugu%4F8yi;e052HTxE!p z_M=ua0WCFq5KFScE}$eQlC?Of$?9OkBqVT7srh_ml5YsmtG*8L(Z9$1v-E61Tp8CS zm}rxpgjM;3J(G|?8S|>K21l&~!7d;^`Yp>Cf0mwID|rknTnWpe#zsw69@{1%f#B2g z`N}x%NKg#&0M@E6nSMgSpCRkAMnYYd+VnW7JD;7Ckj1&^*5eB8oe~tQf_zgx#OxCi zVm2bKj_w=@l{ug&VVUgvY@UQHOwC z)9h@Zgv^gU$;Nzz#wg^&U&G`RDmFkakVz56*^;2hP)&C~dnh6EQC+Ob4HAyY*wTf3 z_#ZO&gp94r5m$(};)49KUyY8Nw4XxWMR z7E~*vN;{Rgt2x`xo=V6|YKxT_fHPNya7~!+#_u!ngqTlbAs0%fkW20cv?VOl=3`qW z(pf;y z%|$csgq{yD*UC>qY_?im!ZPP3*j3Mtkm zeF^KRD~}D9XvU{*cTmdx&Qr8tY8SPdX(t>U#w^!lDL?)9s@o};5-+KUO_pfIlH%4^ z^KL00uFF7QiT}u~6Bd^J33I*FB?>9na<4wOHGQS*vqUGg6$%U9eMyLViJ*Uee#WR1 zCf07pTrs~%G2CX23Cpwq z9I2c;N|a$wa%ime%=1zNoCH#r%#|Hl)#YO=Al?F44r`u*yQutdSyM zHR$addsi^$gpV&*f!1xFl)63PS82Q^oA(nEH9Tz7S>=rnr6>qGVU%~|gqcI2m0Kd_ zXS70{uePTBr$jbhqJf;pPNn&3M2dt(r$Hs)9Xa7;_dd{t;}K)OS`(J>W?0yKiFB;_ z4N43Aten4Du7OIhZ#OeecsYRjXUl)Y6tAyBsR5hfPWE3Sn|`&`UDqK-#EYO3to(=x zC)|7jx^`@r#FTIPX{{b?va8sFiCmhq)Ry+GE-@-jw1aA}lldm>#C!p|c>Jft6mY#> z8|LjfL@Yi}g4)8qC+CQz5A|2?*cj%U@Dq(%!l&ijx>7W%)`*QGm8ac_KeEi(_GIUK}wFJim>qy%r=q1e$*vo>lIYUPvbRPa#jtSGLgbV zm*!%Q&k!W#4I8QqYnW^zg%42IP(z-eQoeXpbHZ|Zd~D1_0>1APG*@!M-y~@XyU}}) zxrUpB?@WnZP%$5KYW8Jg^K`K}6Liv39jeRN*(yj(`z=%%c5Gs<;U?j`b4`*rcj~rg zA1iT|>RO+r_$ABa`ufyuV4MJ`b28FAV>bcsj+nr5jMiHAdLB*0kq`ZLLO_KCX zfz{zFW*Tl124}~=Us6Tae52f;%_GiiAfV)SYp>qSW=VRM!k(q$1|c^IgGJ>-Ni{t( ztlgtc-5^^v!DFCDed%5~A}B<#zPRMoyZ^)_uvYT2#{7I(5)x5asq6ivi+ zVr~#}lQ4)J7v>bEX(~(zBmO ztSYu}62Y5;j8`u{H|NXJwF7vb*?uM&ZW0Ea9$_=U``vVHMl8a3g+TIvEMe{EaJAqD zVFYgyZp2+z4}_U_m7l)-zlhb$R!$-?Ub&94I$!J`lnaw~6jzIltC?dWmuTQB|4~?x z7xvM)8LKuqQJ!1XR#MVy2PxZe!MCBD8X?L?1X5xym@&FS|q_Y#a*rokS7#DYyugcT) z9bA zUECXw^&h};e7>9cCGy#|3V4a7iSzV39Edf8p`=7MdJ+!mQ?9W7rjuMMPUF7<%du(~ z(+dLYkZV3gT*)^N(aC4vPCLbBPeM&sl9#nNgGPBbSzSif<7;LY2v%$XUStV_;)>q) z9ld-ewlgDa_#~8^OmndAX7YQUIF&n*C-ZMv!R&&;+U>}nt>sNjs((N?e?3RHacTnz z88v5k6!LX$){B$5963a9U(4iz!e5{d>BxJric8{;;jhD~4J1U=axTMcwvzU zY!7n_49h-4UTHl7PeDK78}w|7Q|#>iWNERCm9Wxg(LOFu>3Zm+7#kQ{fY=lT{cXc4 zulk!Z>FTqUZb z7FnvJS00{hpNsAj0>!=!Ey)^Y7A)37FSkj729W+Moqf*FSS4dtW&sj(2C{hcYEJH@ z3sf6=K!Z8L!~zELth5`~SPNs6G=zQ<4PbCU|33@M>cRVBVKK3z8iN^%u29oLU z^N^6$&tO1;L6eLB?9NB>phU$-uzw+1$Fu?n^gwrGh6^M*K~*C?eqMSec}*dCM-nG{ zSV{BZ7x_y`K{vE09N~@$^gwrGZq-Zl0^Xam5Dr%_BLaDQ&U<*b`a-WTc@jmpV^2C; zzKvN0lRemOFeLoFv%@4rN4?T%Z^RVDY$IL{#YV%9M%+7!}R+_@TcZ6HjuzLmGOubvj|s&-k8ve z9jxP{nNpD1iR}uuYMHLk^)nrRF%q(JIpLiwPA#W0EKYWTQ1NZpx*TFgfoAt!?Dgkv zmgx&t9>fadtvj`l`GG7%VG<{{2Y|;SQ~vYdKaFxi1N^Lp<=885NNS5c#)DXaoyMwX ziXd}S#FJNnZ3K)9T>yE0Y+;tKWkNycFt|AscL_Cz<|}mmKybL47$wMTdO7ndFdC%} zm+R^SSLQwD6MVh`|Az5j_RjUI$t#WGMFqT#R;}Zp)Vc;0M@QSKV{5|V8bWx9xeyWq z!6bqr(xF@i1wk33wjxoirV{D6;-HQZ6)dxGs(;>qGpnmzV=KAxp8f3K!BFeL001BW zNklYLGh&t=cL99hn>YnEPqvU^-c|)9Qmp*=_`~{=NeYs302z-*Scq5L%I>mG)4Pdd@ zEMG8M5QE`_{S1E%iypt4gYAPWikBw;6J`?(maDE3w_!!%>tTAp;u-l{GxLRPPF?Qd z?_lxto`>y(tE$ g_(Nd0P~3#S$N^OgMscfkd_nJ=S`r45`#kb89dm#vQP|FsS-? z1#f7;p3Hsq5Kom2p~K5D&LqB0TVLp&3<6v@H=TJDP%0p zyaUn6xvLbgK+B~1^QwQ`!8C%%&Q;2{<`ZaJIZ{V+NFifcVoW9oMD0vhDNuI-xj8DH zD_@|({mdem>{eerzJ<1y6DR2psc@!)_hYG^uACRy$Egs&K3aQS{R(}?B!bGv>UXCd zT0Uy~=@6-AEN>rUilWmsL;Vfx;M6c|`9dc4Zi-Y6VmHZE^-HubmpKHNPt_m8DgoD!);N74^(F~exLK&y*cDHBq|U|j z;9sBWH_57POd-f@2Qbe$Y!wMVqf?}VnvgHd=%Rm)dONr=m=+rAu{-4jz^!PznL#*) zrE^M$z%9pBO0!7MW?@h}!33jc+N^HwiKj^xHSk{X0?6XWOduS?(!Xz_pU1!RkbaRa z?tUAqVvx}zRik4!*`Mj6_b=e>@*O}D=M7i_Zo?{6zfVmA;9?SPq+_IyOF?@V^Nhae zbh$axo<`iw;0-ei&@P2LnLl_NmJ;(d@b`9GxpR_M+TA=_s27@iW=>tDl}amm&zx%q zDAO{g4+(4rXw`-mctyEO-$*Yd0gJbm@n(tl1-qO99vDnB0r^d z6T5|>%U>|;WPL^UawFS0BjXZB;CrVH;rS#!K`4i12*UE^HGE+?P5;P{E4j6k&HkrUPDDDztK1NT#R^+IfRRrtwEz?mG5brYLvf ze_i;6v@th zVZ<`s#C((r;h5dSUBRpnKQAF)c_3=FoOweWdBqT|`%1!?^3kv8C)r{+q{aG}l#&@| zx0>U;x-DDuOZc>`nt-TPaUS!AJT`7%!cvAI8!aV!T1C7A~n+@ zGW#=#Vr|&Sv>}mgt03CfEh1qxP0&@ciz(7!jrtj$-r<3r(@swfyCu8a6S0%+$9VF7 z)i!1gnS73+Hb2O?%*bb=v1Fancu0%!h~eA!Z=%+Y2-mH$Po>Mie5DSbF=UX?Lx%Pj8QK>@hlmP`$okiEW`P`beN^Z7VL1z+%xQp z`kZba6I^2A12Vd;;t58*c*Ce{4uI&+b0G<<%1MV~%wn_>N=d(vCDaO#i)nbnsB{j3 zNYB43gt*=DUiyqq#Pi{U>#x0&zy}TeokOp$cpfrZ>4Y<*2IecJ;0>eF$$1~7mHVY6 ztgx9*qbJITgJ!$0>nPMhX{Xm^aR;hdT|LnlX1-F3_j8yqq_esRWerQrQ*syDX*PP? zHeASAihE$+n`9L)XE}98%?ktbm0A?7X1*Z%SAewhb1@04jkk{K7E^paXj#3TYF*Ce z=<;b6cVw8mfqG?piup=03U@MHkoVr(grY%m5|+VQNz2iD(h9gc?7mp1o}1DU^}3wq z;4oLLbdHd_MUl=A8jYKnEyx0gP&)dCoP^cMTSpb4wD;-66X(^rSZlLBTBo@+Hh0ze zWa4QruT@ioTb*Krt?Us>(GD_MkT>KNqxAH%Dmfo|E-qpzm$e$YJvYX*m-oLuk>y#f zaLcUs*{>Ihuy@{-Dvgj|1-HM?Nh?>FXZ^B`kxl zj`jnyx@EEr-wXuD-H*)IE%w_ktM7t$v}>M$&IPVH=IMKL&~M>i*WUc+z{1~0y%&5| z*KNDyiaF#S4+d@y+e{2pFqm8w%vb8c0e1p9=x%gNN?6BuoRAP;9?uApGygM~x-Da- zAV1|JnAUzJDPeIDixA-DD@j_`hx563h>3#yj9puBKKg1UsZyJpK12v2o+(L6R*N%J z$^mzRJLqm42}{x?!?cZ7LG;GQKQ!bGb1s}fohADJ^!oa(JCV2U8W%m?{E3+?BmDOHum2cQX2m}JYcLDTfj?q{;Cr`6D>`sVs$Qy27 zSZ^-{s^Er=Ob_JU0KJ(r|5<1iC|hMN4!aYg(ptN`;r4l6mIIZLFXWKLu_hl$x-@~p z#bI|s6hh!|`#i6ah8gnLGC7dN@n(Kp=#BE`v%^*lWf5R!zB z5*9(V|3s}w5i7IS(7*`MFLjzrJWI?tKGr=uv9&Yf_?EFW>z3c zkXMZLJE;3ks-hXrJ*J}(q91}$v0~H(cJih;k6D2vL+)OzUxLJ^pMTsZ9Hyxeq7NSW z$gxUSl9YAzE4Pq4ybn4%GIGkuyKVC3z!o~vTQ2^)3$Hq zDw|=Zk={ngQsbEvEJ7OCwK0X;m=Z|x96-B9siRD=y4{b{-UwMr&I+DWFjP3fs#$V? z8G)q2Iy8Z6tP(76Ro|FsafB=tCQY*Z^!z5gY3q5I4gm~nctvtl;S^^Z@iDRi$P1VEl*+kh^tQAGWk3TM z*6_McrL&yvM3hPgBjV zXHZxc`7~4Wle}d;LQene z$+AuP)K?X(qXYta3HW)8lQ;g#Zr{I%o&Z|fQ6?`+E_5lM{A^8O4`mS0gU81+oNe-! zyoFs~Nk;%}mAor2P8zO~|7^#HIPDH-&hd~3IGb%i;6#|cCG-Q(n!IsXcDs9!3~006 zVYWMJLW0y@>2$2K@SHDiuW7)24#MsJLaB6K_h1F)c*qY{&0^cb0tnGJweZYHWpC$s9~5?7Z2SkTQ@i4k+M zom}{AW<%lu#SzF&v+B1FJ~whv;_@z`3xIy!k{C1mO!%vs$QcSGki9^to;>o*xhoRa z_k9LnK}XA0ON<)#H2LuVnnJY{Ng&Ha!r-eHhdKii7kJkWdI0EY%N~hw;|P%vf7R$? z@+go6PyZ?M$MfF@of21g{T4a^=&NL}$mHndN{i=C`J5C>ATuuSB)LQK?}K*x-css6 z^d@oO=&a;v^5To*6LE&S1DU)7AL=G=y!d_avB))Mz$lEcy+CC6d`E`-O}E!Y(FD?L zuc9Z&885V-6uHO+2dVuq!ir*%0TlR*+(?TBWZYg|BVYXHX|u>xE?!6FhcVX5{DR~R zk{w@ipB4*Ph$~Ke^|BA$GP~%t)O{G`u+U`5y*ad40PR)Q{6dd!R#5d}oFhW><U84WOR4rSUg~{B` ze;^+ybG+UD`wi53 z3)Qqt5c%_JOp0A|$6_ix@~c8_O0By`_MG29oJ$I!5LbMFsGr|ouFGBaqttig+Y-6) z<&2O&-{3w|8=#8eeqLt3Ny066-B(fFk$;B-r&jM}QYcd!pfct%q&Sfol6yqNeuUZ% zGx&qx?0S;RpHob2xK8GpPxk7n{we^J>iR1;;pB23Y)@-Dj zgAU7Jn&8 z!UhAPcR|s1Dml#QV1eum?5iTZF03tbi((C{xx%->bcntjhyDttwn=!0^@tptmL8^$ z!b+Uc82=5XHJ#zM?2S;ci7F2BT30SR{+QR0rqlihlx-=liN{MHr<4@CFJ zWZU$e^VLzxVLr9qJ49#tW~7f_aV(~G!wMFQzm|@%?wP0$j#18GE*EF&iOdXQ_^k8| z;rM{c4QtpbK0S}0Bj;wKE7V6#hgmfEh~JD{6F=I{v6H$DIxN$CCj2j1H^b9dab{z| z1f0=nPF`i^iTr!qE2!GAj-&GPwD&TJH#2RKDat$Y>z~ZL%2bU{{B9Yu$Bt>QOVzgS?FN?DDuLQOz_e|Jx5yPUHkez@o_R#B@# zhh8y+sh$x*C9iH*YfcFE3zkSmtad&R0maNRWdTH9|I{-leR0xwEr zXPA2iwe?AZDx0TpEwvbQSeEAHV2H*V6Y*L)3)ta zo+oQ-{;{wp+)00-_=my%82{;NuIGv}8>o0Wbr@2uQ>Vjn{)-bLdVDO5FojfAuBp%+ zB0zgJKdSTny?g~#7;+sbP^TW8WMG3Xnx?({S*V;qlv$!WJ+q9dvx^GWQG+4brXqEs z*%PWFee0s??%!|GbEsqdi@Su9KB^g=PUO;ljWwtcfgg(2BR2G>h#!rM&iAzxiI z@&mhFFO!cH+Db(SslSkJpGqB8ZG;@I>xrx=_vuJ}2b>J`RI|O#G`a-^y zYgDQck0wdux}MPO2{9u}B1fk$R?q&{^(F9EDs8AWE2+Iu!G^s`ed2gRCfC_W!ppFC zQO-nzjqGckeW=vGBHK1nd7*~V-AYx9hy4Cz$k##!k%};!3^Ar%f2W6(+Eu$tsk=}` z$sVi8df_x{!NeaCUUfFg1c3l@feqJpCHGVF2lki#WFh#`j%LSndBvLfo} zL4;8$UCIG<>aeccu};7(%()I1Z8r`Rg!!!@8{#kwm+3Guh)m~=ks}g zy$)v!3m0uHu53QG1$ljyIHxM;TS${~R@kpOFR_w;@V%2+q^j2JvJEk#o!3_hm77l6 zLZDBj)d?@LlCO_NmP&PW-sEeYyuM1fGbvOpMA|3qcfIu+5?%ode!HiM6^(k-^^REw zc`g;;m-hOqI*p!%*cFyR+)J!3LSCUmSys~$OB)sJlshdx&a*3{P2B4%!>?#r$d$iS z+^G{QIj`LQh|lI~VU42{D3qn@}|*1c)lEN9=7q+`}L-Oe+ota_`w zSGU{t(65lLyi{K040C--6&r?@&R*VSCGx%1gv;)~#FM6i*R~#cPv6HUXjh=oCfD0uL3@t-wbgc2FUo{%M-F8mD z$BS`s%)v!L6}f#);8R$cN3#L}(mwtC_D_5>9i*~tl-GZJ*2?;5D_Wm@|C#|;>T=F5 zaT~lKlU@bhI=EM28$ETC{;G3%$ZB>?uvCgwOB9>GAp*F6(`x%N#1DD6;*tG5LhGSjL0Bh>?q4DmR3jaNnWl_y2ZED0)P3ch_S7FJ1a0Y>`_bOn->UmHRknL+t5_-6u@$Eo3 zc?D8Ww+ug`7BuYKps(9za`kF_@33aV(`k12hd95kW#b;HDO$kzb|8$hy;8G*$?p1i zrS*f~@oMZp!;>xAdGuN)hyOnI%HhA=#?Mdt&fCS_cxAjO5T4MHqXAF9p&fL!*7Ewg zEq0S@aiUI@n}CbXF}uU>8yw|Fr6cp##Rh0D<3)i8Qa%+M5Y?`W6of8a^3H#K=kd31 zoSxpNEeah!HnfcNdYo^*ef;0A=e=G0Omt~sN^W|lQJz3#hj)n0h#PiZC+Oe3i?^r$ zWwqFE-JiWXGtt_ZkS(2>#*T@ZyR-Li*)3N8^zDoH`2VhZQb%6}?D!?k2}C2iMDCwq z*MCP($kWp{*f%uoe*Kf0?|2LDmN+ECj`LmU@S_DX-yznVh3We zPY8hB!I&Ip{1p&`%tFC&!9F2?7|cJHoRiYm#8QSJJi(g48jU__@5(w9JN zQqG7D4db8qN(q37Mr}sXQF$PRwgh4(cw9rkh@b8N5T1KUbW9p{(Uic4$SM&X9n~Jb zPY584@n^C#vg9N^34EC1QrYQIH^4k203o!?{q7*+8Gx-Ss+64{)mI#~)Chph>aACV z$0OqzfUVemM0kW$_x_qD0kF|fzw~S@WIO|~CF!}+Q^aup0%ZbVE#adX0?ww>kH8iQ zzf4#i80~(JLIJR9)M6C>hbPwufjE$UnQ&Q$wVqM|u)_bP_(0X))gyAu+4+3$+Wx{1m=6lo&AX&T3ND@}>-cBb1 z@xx`pfL5kr0dm!McaVZy9|Yo#%Y-XavF2$RKqmJL3CQ(9AQ7@N$d+ZEA1E3?o<1k( zw`^NBT?oYAi9@7I;19T|1=nCTJc|XUR6~=3jztlQTKNyyXhT30{2z&j^ph>5@c;7XWshrL#hYR zySck$-Mi!MS@a)}SR8eKf1%Jz{Q!E#)j^K814)!uK-RodXW~L3pj$7wI>_;MAgL6S(t9I<8^?+pA!&LY8S{=-6 z0Cc6c`%9AT|1y}~4kS@gC8@J^W&n6ceC*zG2dA4MSQAWd|hPNoJ0&^I)2C0<>+;Lz1mkl26kC zN?_*b2A;1dC_uZs%oSaa>7syAGLMiz>p90MDL|Y0ra1Pn9@9ku@pAlBw3)^8~+Kts!` zff{maU)dEHy5%*eC=v;&YZ)n;qf!6`%s?X{6C6HKvyo7odI@SzZOPpW|16 zIxrC{*b?jaEU^H!FRxy(yb5ysis@H?YA_Ki=n{*wSO90Qw0Hc9=~sZ74r1*lm4cqd zVlEcI@=9CBuQF*gKuuE87$Osl!P!TV0qQfzV20q4b%5hn0J`e|d;kCw>q$gGR0pv% zl2&zK(h5bZYF&~+s1STKofG9*AR|zfR7XcNp->ANb-bnw20mUw4q`@i4{)G zl$Xi_l4YE4;)IvWbOt~>@)_$Mo`s#O5v+6N)SklOLi^}M%*4eOj7|` zRDPWN;=DVci1C3Y@+Fc(r|Bs`quYd^kYLfAcdw@nfwx|5YbxW%BC>7zg-qum~|A_f^J zX(B+6iVDfMSTviTP@q6)3w+KwHibW z!k17Ka2Tf3PGtgO*n~h5!e(Pifb5`1&6qB=L`7pD7KUQ@2m~jB3Q`%UV;6L$sZ;;E z>a^6>LM6L*KkmKH^CQDgnSIYWbKY~$yUja=@Yuoj)DAIXGO8*nWg&>HtzOQVq&Kgg zmrCKs4vZRXpQMe;WFUw#FXv2t;62r?jRpTHlh`FPOj3=vaUklf#LA(K)qX%ug?~Dh zyeB41mgQFv2UcQfV}a&XG1V@Wc_0qfRhV_x#)8Q^nEb6ski*w9tJldp5EF|QhTFNCpUT(Iq-E=$f@Q_93S{4|cah ztj$^>4CbS^WuH7u6dl}~cE0m5<2m^S;?2T_JT;`UzA7YoSA*|6+j*J4PHS!7YUzXWA8jQ9+H5MT=-eKcaFxGC7OMoAjR%pvRA#kK+%xMkEg4wbN@MzQLiIKrM+VX|`O*y-N z^|*5yoSK<(2=G|Xc{(S^dDpR)`?5G?T3xk_ZF5G0v%=Fj!2dO~Mx+e3#%i~M6xCJa z)p;5R_$l6h4t^f%_cA)=;}vsPL7OpE<^VLYN-~di^@zMqIk-J)?n?U#(8P*VA1fof zQ(FCcSK3#ACRX$e*+EL_jCY)N2DPsMO{{3@Ok`h_>M6FvH~ZS0KJ6<&6D!L0{H1lb zj8E~rl)bpexzoM^%7&d-1+%LwX$dJsabRz1rxRBo3ueg^KrW_xov?7W^%{Do@I&qC z9nM<8SltffYRaOuf@lE^B(f(I0TgQNs@YI`LEBee9t85RrlLw9Eu_XT-`S@YAZX_& zK5KNk3fh8Rxk`Qj^0I7$SX%hYLfab%&Um|v!9v@#MQ#A{wQg>;a9U_h!#xKT2IOyl zcVDOTRA|+!*T@V&05;c(sD-ySfe+3bii zfn1C{IQzL1R1C}OE9C?rFiYo)t3_&L^>$>oD;JpT)Rop%ku07g9{_=R%G%N5O=P8# z_Z1C1nFBouuizAomvMmLEu1I17STt|w>+rBPuSgk;j*(*L{^Ie1u@&&(W2UwZolbe zXdYvGraisODJiD4i(~q#Yx=~ zksm06*&791MHY&yxLEL%s1Fo}VfT{yDlu_e$q}Q0_Pu{Q?N@KO9f*g`i^biN`c10E z!uMEwEjT>j*IrV!hTDPSve~`lcBVVJEhCMr7c(tZF_hel^@iJlVp}+GoA6t5yMEXF z;DBNza+??)To|)Nv<%qX4wS@}4FYgkXiK$N`5qOA$M+`g`AwIFXKii=N~E%WxgcCF z_k~xkweC}%gxkK>YgcyqEtiSqbJvOSK*=nv6Nk&JmGzQ3C6p6a+hLhtyFbvlohQ6@|zudC2(dsLp)Sj2f+D6&eUa_xYVs>}I|$&OFtk;c8$-1fPioU_5gl+($dgrB zf9yN;_6dbe>797}RNo&P{UXcwcF?zjfO|qFIsKmM$R1MTl*+N2EeW&iWq&)kL@Wo~ z6Ox0ryO%y4w3W2DD;NepZNA&)x94^cAUBokrwP&FXl4y{b@YrMR{9iS+NyoHSKBHa zrnwyi%9i&D!{q(mi=*#a=1`~w4DXKK>Ghsqcx(9s!>>NMG?5um9_3>sGjZvY(>wf{!e_<$DPlKJ z_NG@<3)msm*gM?bli9CUn&k3@@0(WXA-|uHs$RWH+y+9y%7&0nqYR|aw!C-J;;f&v z`{mZFe@=IrJPft@bHr>QG-huSwxiI`N;N0D`@OdFzxHK%+7sy^l~wp{nk8NXVN$t% zhR_`mJ1>87;aqmmfYx^o4rb4txqjIQdsJA>0EExX)m6fGr0g0>C))RR_ivA7$10m_ zPW9Rr8ZA}x7K+qB2+c8y70p8H^p)XD=d!Oy|Jj`v4rLykyEJ^|O{+qqIefKQlm;(1K%XgYngYq+oD+{Ak~P97+O=XiF%dh*756X!bm zhP#fQZnASdw!>F8Ujfmu=oulM=bvwAdZYKs^*e7}8%=)upgS|zf4-m>iu=#^4}RGF z;M?TrwYTnEzta18lgmH8Q@ce>2BKohthK^AkJ8vQ^wIJ3YpHJ%iRR{y+y9=N=;>+g z?!J}DWXAjZZ}0n;V?WeQ#~%LM?f(Ap@BZ7Z?(Wu}o{8kS_K%w{Bog1GUP~XpJk-?a zZ_A@>oa)&@AWAGA1xn6hQ6PF|RxB6ZfzmPC4n)(^8c(+YrBb(46b2${>taD3D23W( zA}|nPvo{I!K(X1|4n$q$db{0$qFV3^d)tBNTT}0YLZE1-Rjd+sfmrZCAy6dMD;J8n zKx`~oStalTg;rJL(?K9!=6InHD6sjP#abYCw*E}`2MTBL7I7AcC67P@g|fkB1|YVk z%(4~>D1fydbp~Rsa_UB@00`E`^&WKwlvoR-10Xmn>XlajHje@UvR4$~q3Ls#SU@1< z)pQXR;NL8F2l8fZJHU@ESy?ST0Lm)>B^FRF<<&f|;s7YIfB<=P5I~6qD6asDTw+y8 z7l88WAMD-fR@+z-0N}BNjdyuBwu~1r*e0wA1Wxn*?={K%=$<|&3lJ|_zV8(zRn@sw zstd4PjYx?FD6asNSinKbtMQG93Gik&4@xZHcjeVXL$m~VmyvOI;MdJTuo zr_G{>2(UG0m!G5-$h-FROf&@8s#13?y+EE_UtWlW09#k652P5#t4+5c3Igm#JeFo4 zkA`*e4`8Py)~j3t`SLoB#Xf)?yP4TN3OQ1VTsa7^51nRN(t&(9TAYY^0DCgGwE^;= zZS57nUfJ3JnP)Ep!2T8LLkS47YhW(}z+o(-V_68Y=-7{g00%T$xCk0DXX3{}fCDq{ z4jI#KRz)^|gDcfsp#zz*2~4&FBt+adj0IU3y=u7<2OvodV}a2t0Jg6B*p{Fm#iLhK zOGN>as8q8V3sP!e^a>!kmTrQE^r`f1y#h$K&eYllNR`vDBXR*Go=zd?4Fa%z%cvr6 zLGm4sd*T&9igdzL$qV!b0oblmttEkh-XH*5*06mPl4%m%h)@8jH4oNO86?e>ouU9~ z7xxXkLxQ+(5Fi_@#)8CXhbLkZKt_~qSFbV~9NO!uRuYc@vSeg$0~}U)))0vRvUiMC zYdOY(L$Q?sz%dr!@Ctypx^RpI`#-!o6MF!%uCXY~c(5<0UmRWm>CjELroB_zAVz7}0VHeiZst5y+UrQ73ux;g8 zEVcmT+*!9};vKf;xOHo;9f1FQpLoBL7GWE%n&#R8_}g+}$2?=(MQvP> zA>re#!LEJn0Q^Ab(qDz}A#1Hc0DkVXRw2Asd$ANd0QjXsFFKMj;jJe9dP&>>;P;GU z!5as!hQVCK0N|~v!BFyq-wa+&J7NU@@6%{r%b@TxpTdzS0l-JZPi=V=el*tpS$qKC z!wRwA3gO?%k+F6F{I#6J z)L7PIkyppVODh=wP-DS1tE;N79{@ELsICA|V}a@l05#TlBKwkUle=!ww+_I5UDTtp z986Xn`DYM-11ZG|cj=Hpr&0aF_YJ_|6yoqoJ|;`f7d^Y$0XV!yb08~|4cCj<7Y#sC zjGkA=k~8Ucym}t_mH|kXV$IMyX&!11tZD}!kxB-#Naxtq%uqW3iPo47UnOi(WE~p2 z0w4uC!QGLxO)46LcN&8Lq(>CaV*XfW{mEpAE8wDVp&U%Yaayd!U zj%ssXCjhB-GhJ1rbP{uPwVK}eDgnsGK~`wjJBgUOa&!eiri_BVJ)|7+hryPqD*&>n zu$&HEsKWsq4?-6>1CU|W+ZSW+?A7_pZPk|tK<4Qdvd6yQ(iaCnUKEzov2E|{)TGta z7X%=8O3P`>0ta?BbY)9B0C`ocFE-}h*=}*Q`BE?XwgAYvc`qC&ve=I6S)zE6zk2F(f1rHx0(*F0ALq7wZ+gDhy3kfSkJl*2Uh^FL#2k<_dNY7 z*uRYJVE}-=nD-v~r?~8f<7*@E`~O9-ry&Rc**0I^K1PGG%4ZLU zR*$#Kxi<~~@^qY4o2s*RGikN%hk-*Y0LZV-eGonj>~z@9=7qsS7~H!>5CHg}i%~BK z`vbolen{oIHJjFS0|9^^DV*E~&1iM*V#Bu;R_Cjz8Qh=vIS>GNgYOesi@p)9pA1=D zx1#S;RwXYA0Pud*W&LXyt=2Zef8W5q{#I9gt>09=7XZLE6dS#uIU8@9^#K8ZeVUKr+SkX$Lu=E{#8iBxy=grx z9>0F8s^*?90B~@{QCtrmzr5TH*X>D~4yx9xyO%GIK|LO60RjLCcGkJMuLsZJ)5CbR zIWH&Z_QT`y`DQhKcnY7tl~gyK3(pDwNU3?J@wrzEo*%=fm;QJ)xH>QIp{H0WpI;4D zDexn}_YWLTkiGP+sDy?X7x6J|1#GhsHCm**E16%`N=5El~@)6vn< z=70mF3zXqN8>j@RP#mZMsEuD<-k8}$&WuTzn@2=iMORXYb@cSlQ7{Td!9W23V)}xx T0#~DP00000NkvXXu0mjfG+~vo literal 0 HcmV?d00001 diff --git a/godot/addons/phantom_camera/examples/textures/3D/target.png.import b/godot/addons/phantom_camera/examples/textures/3D/target.png.import new file mode 100644 index 0000000..6de0861 --- /dev/null +++ b/godot/addons/phantom_camera/examples/textures/3D/target.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c3mskbmvnpwux" +path.s3tc="res://.godot/imported/target.png-878c5e8d057c8a9a4c2322d4ab88e9ef.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/phantom_camera/examples/textures/3D/target.png" +dest_files=["res://.godot/imported/target.png-878c5e8d057c8a9a4c2322d4ab88e9ef.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/godot/addons/phantom_camera/examples/ui/ui_inventory.tscn b/godot/addons/phantom_camera/examples/ui/ui_inventory.tscn new file mode 100644 index 0000000..cddd377 --- /dev/null +++ b/godot/addons/phantom_camera/examples/ui/ui_inventory.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=3 format=3 uid="uid://dg7rhrymsrrrm"] + +[ext_resource type="Texture2D" uid="uid://b7cs6me43ufh3" path="res://addons/phantom_camera/examples/textures/2D/inventory_container.png" id="1_pi2dp"] +[ext_resource type="FontFile" uid="uid://c4mm3of2mc8o5" path="res://addons/phantom_camera/fonts/Nunito-Black.ttf" id="2_0rdcn"] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TextureRect" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 4 +anchor_top = 0.5 +anchor_bottom = 0.5 +offset_left = 28.0 +offset_top = -255.0 +offset_right = 908.0 +offset_bottom = 183.0 +grow_vertical = 2 +texture = ExtResource("1_pi2dp") + +[node name="Label" type="Label" parent="TextureRect"] +layout_mode = 0 +offset_left = 345.0 +offset_top = 12.0 +offset_right = 535.0 +offset_bottom = 60.0 +theme_override_colors/font_color = Color(0.356863, 0.105882, 0.133333, 1) +theme_override_fonts/font = ExtResource("2_0rdcn") +theme_override_font_sizes/font_size = 32 +text = "Inventory" +horizontal_alignment = 1 +uppercase = true diff --git a/godot/addons/phantom_camera/examples/ui/ui_sign.tscn b/godot/addons/phantom_camera/examples/ui/ui_sign.tscn new file mode 100644 index 0000000..1b891ef --- /dev/null +++ b/godot/addons/phantom_camera/examples/ui/ui_sign.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=4 format=3 uid="uid://iq5xd1ob1res"] + +[ext_resource type="Texture2D" uid="uid://bloouh2jtndx1" path="res://addons/phantom_camera/examples/textures/2D/sign_prompt.png" id="1_tftrk"] +[ext_resource type="FontFile" uid="uid://c4mm3of2mc8o5" path="res://addons/phantom_camera/fonts/Nunito-Black.ttf" id="2_y5454"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_r4h3u"] +bg_color = Color(0.470588, 0.6, 0.45098, 1) +corner_radius_top_right = 47 +corner_radius_bottom_left = 40 + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="TextureRect" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -273.568 +offset_top = 47.0 +offset_right = 273.568 +offset_bottom = 413.0 +grow_horizontal = 2 +texture = ExtResource("1_tftrk") +metadata/_edit_group_ = true + +[node name="Label" type="Label" parent="TextureRect"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 25.0 +offset_top = 64.0 +offset_right = -25.0 +offset_bottom = -88.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_colors/font_color = Color(0.207843, 0.0470588, 0.0666667, 1) +theme_override_fonts/font = ExtResource("2_y5454") +theme_override_font_sizes/font_size = 62 +text = "Stay Awhile +and read" +horizontal_alignment = 1 +vertical_alignment = 1 +uppercase = true + +[node name="Panel" type="Panel" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -240.0 +offset_right = 240.0 +offset_bottom = 200.0 +grow_horizontal = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_r4h3u") +metadata/_edit_use_anchors_ = true + +[node name="VBoxContainer" type="VBoxContainer" parent="Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +alignment = 1 + +[node name="Label2" type="Label" parent="Panel/VBoxContainer"] +layout_mode = 2 +text = "Example Textsdadassa +" +horizontal_alignment = 1 +vertical_alignment = 1 diff --git a/godot/addons/phantom_camera/fonts/Nunito-Black.ttf b/godot/addons/phantom_camera/fonts/Nunito-Black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1081731539aa811b4f0e69aa547cff7f7c2a3ecb GIT binary patch literal 131568 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