extends SceneTree const SANDBOX_STAGE: PackedScene = preload("res://scenes/stage/sandbox_stage.tscn") const TOWN_STREET_PATH: String = "res://content/stages/starters/town_street.scene" const SKY_IDS: Array[StringName] = [&"sky_clear_day", &"sky_cloudy_day", &"sky_sunset", &"sky_starry_night"] const CAPTURE_DIR: String = "/private/tmp" const TEMP_SCENE_PATH: String = "res://tests/phase19_sky_camera_tmp.scene" func _initialize() -> void: call_deferred("_capture_sky_states") func _capture_sky_states() -> void: root.size = Vector2i(1280, 720) var stage: SandboxStage = SANDBOX_STAGE.instantiate() as SandboxStage root.add_child(stage) await _wait_for_render_frames(4) var town_loaded: bool = bool(stage.call("_load_scene_from_path", TOWN_STREET_PATH, false)) print("VISUAL town scene loaded=", town_loaded) stage.call("_on_grid_toggled", false) var camera: Camera2D = stage.get_node("Camera2D") as Camera2D var sky_view: StageSkyView = stage.get("_sky_view") as StageSkyView var spawner: StageSpawner = stage.get("_spawner") as StageSpawner var stickman: StickmanRig = spawner.spawn_stickman_asset("res://content/stickmen/break.stk", Vector2(0.0, -400.0)) if stickman != null: stage.call("_save_object_state", stickman) var scenery_controller: StageSceneryController = stage.get("_scenery_controller") as StageSceneryController scenery_controller.begin_background_ground(&"finish_background_grass", Vector2(-900.0, 0.0), Color.WHITE) var ground_press: InputEventMouseButton = InputEventMouseButton.new() ground_press.button_index = MOUSE_BUTTON_LEFT ground_press.pressed = true scenery_controller.handle_mouse_button(ground_press, Vector2(-900.0, 0.0), false) var ground_release: InputEventMouseButton = InputEventMouseButton.new() ground_release.button_index = MOUSE_BUTTON_LEFT ground_release.pressed = false scenery_controller.handle_mouse_button(ground_release, Vector2(900.0, 900.0), false) scenery_controller.exit_tool() print("VISUAL action context stickman=", stickman != null, " background_ground_count=", (stage.get_node("World") as Node2D).get_children().filter(func(child: Node) -> bool: return child.get_script() == preload("res://scripts/stage/scenery/stage_background_ground.gd")).size()) await _wait_for_render_frames(4) for sky_id: StringName in SKY_IDS: camera.global_position = Vector2(0.0, -400.0) camera.zoom = Vector2.ONE * 0.5 stage.set("_sky_id", sky_id) sky_view.set_sky(sky_id) await _wait_for_render_frames(2) await _save_capture("sky_%s_reference.png" % String(sky_id)) stage.set("_sky_id", &"sky_sunset") sky_view.set_sky(&"sky_sunset") camera.global_position = Vector2(420.0, -210.0) camera.zoom = Vector2.ONE * 1.5 await _wait_for_render_frames(3) await _save_capture("sky_sunset_close_pan.png") camera.global_position = Vector2(-620.0, -740.0) camera.zoom = Vector2.ONE * 0.12 await _wait_for_render_frames(3) await _save_capture("sky_sunset_wide_pan.png") camera.global_position = Vector2(0.0, -400.0) camera.zoom = Vector2.ONE * 0.5 await _wait_for_render_frames(3) root.size = Vector2i(900, 700) await _wait_for_render_frames(4) await _save_capture("sky_sunset_resize_900x700.png") stage.set("_sky_id", &"sky_starry_night") sky_view.set_sky(&"sky_starry_night") await _wait_for_render_frames(3) await _save_capture("sky_starry_night_resize_900x700.png") root.size = Vector2i(1440, 720) await _wait_for_render_frames(4) stage.set("_sky_id", &"sky_sunset") sky_view.set_sky(&"sky_sunset") await _wait_for_render_frames(3) await _save_capture("sky_sunset_resize_1440x720.png") stage.set("_sky_id", &"sky_starry_night") sky_view.set_sky(&"sky_starry_night") await _wait_for_render_frames(3) await _save_capture("sky_starry_night_resize_1440x720.png") root.size = Vector2i(1280, 720) stage.set("_sky_id", &"sky_sunset") sky_view.set_sky(&"sky_sunset") stage.set("_cli_startup", true) stage.call("set_mode", 1) await _wait_for_render_frames(3) await _save_capture("sky_sunset_direct.png") stage.call("set_mode", 2) await _wait_for_render_frames(3) await _save_capture("sky_sunset_play.png") stage.call("set_mode", 0) await _wait_for_render_frames(3) stage.set("_cli_startup", false) await _save_capture("sky_sunset_play_stopped_edit.png") camera.global_position = Vector2(420.0, -210.0) camera.zoom = Vector2.ONE * 1.5 await _wait_for_render_frames(3) var saved_shift: Vector2 = sky_view.get("_motif_shift") var saved_scale: float = float(sky_view.get("_motif_scale")) var saved_camera_position: Vector2 = camera.global_position var saved_camera_zoom: Vector2 = camera.zoom var saved: bool = stage.call("_save_scene_to_path", TEMP_SCENE_PATH, false) var reopened: bool = bool(stage.call("_load_scene_from_path", TEMP_SCENE_PATH, false)) if saved else false await _wait_for_render_frames(4) var reopened_shift: Vector2 = sky_view.get("_motif_shift") var reopened_scale: float = float(sky_view.get("_motif_scale")) print("VISUAL sky save/reopen saved=", saved, " reopened=", reopened, " camera=", saved_camera_position, "/", saved_camera_zoom, " reopened_camera=", camera.global_position, "/", camera.zoom, " shift=", saved_shift, "/", reopened_shift, " scale=", saved_scale, "/", reopened_scale, " framing_matches=", saved_shift.is_equal_approx(reopened_shift) and is_equal_approx(saved_scale, reopened_scale)) await _save_capture("sky_sunset_save_reopen.png") if FileAccess.file_exists(TEMP_SCENE_PATH): DirAccess.remove_absolute(ProjectSettings.globalize_path(TEMP_SCENE_PATH)) stage.call("_load_scene_from_path", "res://content/stages/starters/blank.scene", false) await _wait_for_render_frames(3) stage.queue_free() await process_frame quit(0) func _wait_for_render_frames(count: int) -> void: for _frame: int in count: await process_frame await RenderingServer.frame_post_draw func _save_capture(file_name: String) -> void: await RenderingServer.frame_post_draw var image: Image = root.get_texture().get_image() var path: String = CAPTURE_DIR.path_join("phase19_" + file_name) var error: Error = image.save_png(path) print("VISUAL capture=", path, " size=", image.get_size(), " error=", error)