# Entry point. # # P1 shows one exported screen, statically, so that its pixels can be diffed # against `sylpheed-cli screen render` of the same build. The boot sequence # proper (splash -> intro -> title -> menu) is P3 and is not here. # # godot --path port -- --screen=main_menu # godot --path port -- --screen=main_menu --capture=/tmp/godot.png # # The screen is drawn into a SubViewport sized to the export's own `design` # rectangle and shown through a container that scales it to the window. That is # the same separation the project settings already make -- design space is # fixed, the window is not -- and it makes `--capture` exact: the PNG is the # design rectangle itself, never the window, so it is directly comparable with # `screen render`'s composite with no cropping or rescaling. extends Node const DEFAULT_SCREEN := "main_menu" var view: ScreenView = null var viewport: SubViewport = null func _ready() -> void: var args := _args() var export_tree := ExportTree.locate() if export_tree.root == "": push_error(export_tree.error) get_tree().quit(2) return var name: String = args.get("screen", DEFAULT_SCREEN) var screen: Dictionary = export_tree.screen(name) if screen.is_empty(): push_error(export_tree.error) print("screens in this export: ", ", ".join(export_tree.screen_names())) get_tree().quit(2) return var design: Array = screen.get("design", [1280, 720]) var container := SubViewportContainer.new() container.stretch = true container.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(container) viewport = SubViewport.new() viewport.size = Vector2i(int(design[0]), int(design[1])) viewport.transparent_bg = false viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS container.add_child(viewport) view = ScreenView.new() # The export is a 1:1 copy of the disc's texels and elements are drawn at up # to 500 %. Nearest is also what the reference renderer does # (`ui_layout::blit` maps destination to source by integer division), so a # filter difference cannot masquerade as a placement difference in the diff. view.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST view.focused_id = args.get("focus", "") viewport.add_child(view) if not view.load_screen(export_tree, name): push_error(export_tree.error) get_tree().quit(2) return print("screen %s: %d elements, %d in paint order, design %dx%d" % [ name, view.screen["elements"].size(), view.screen["paint_order"].size(), design[0], design[1]]) if args.has("capture"): await _capture(args["capture"]) get_tree().quit(0) func _capture(path: String) -> void: # Two frames: the first is the one this callback is still inside of. await RenderingServer.frame_post_draw await RenderingServer.frame_post_draw var img := viewport.get_texture().get_image() print("drew %d: %s" % [view.drawn.size(), ", ".join(view.drawn)]) if not view.skipped.is_empty(): print("not drawn %d: %s" % [view.skipped.size(), ", ".join(view.skipped)]) var err := img.save_png(path) if err != OK: push_error("cannot write %s (%d)" % [path, err]) return print("captured %dx%d -> %s" % [img.get_width(), img.get_height(), path]) # Godot passes everything after `--` through untouched; take `--key=value`. static func _args() -> Dictionary: var out := {} for arg in OS.get_cmdline_user_args(): if arg.begins_with("--") and arg.contains("="): var pair := arg.substr(2).split("=", true, 1) out[pair[0]] = pair[1] return out