"""Main application entry point for BoxedMan: supports both GUI and CLI/Headless modes.""" import sys import argparse from src.config import Settings, CalibrationData from src.gui import run_gui def main(): parser = argparse.ArgumentParser(description="BoxedMan - Interactive Projector Installation") parser.add_argument("--cam", type=int, default=None, help="Camera index override (e.g. 0, 1, 2)") parser.add_argument("--fullscreen", action="store_true", help="Launch in fullscreen mode on projector") parser.add_argument("--sim", action="store_true", help="Simulation mode without webcam (draw obstacles with mouse)") parser.add_argument("--no-gui", action="store_true", help="Run without control panel GUI (direct Pygame window)") args = parser.parse_args() settings = Settings.load() if args.cam is not None: settings.camera_index = args.cam if args.fullscreen: settings.fullscreen = True calibration = CalibrationData.load() # Launch cross-platform PySide6 GUI by default if not args.no_gui: run_gui(settings, calibration, sim_mode=args.sim) else: # Fallback headless / direct Pygame loop import pygame from src.engine import SimulationEngine pygame.init() flags = pygame.FULLSCREEN if settings.fullscreen else 0 screen = pygame.display.set_mode((settings.projector_width, settings.projector_height), flags) pygame.display.set_caption("BoxedMan") clock = pygame.time.Clock() engine = SimulationEngine(settings, calibration, sim_mode=args.sim) running = True while running: dt = clock.tick(settings.fps) / 1000.0 for event in pygame.event.get(): if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE): running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_b: engine.capture_background() elif event.key == pygame.K_r: engine.reset_pegman() engine.step(dt) engine.render(screen) pygame.display.flip() engine.close() pygame.quit() sys.exit(0) if __name__ == "__main__": main()