|
|
@ -15,6 +15,7 @@ FPS_CRITICAL_THRESHOLD = 0.5 # Critical threshold for triggering strict actions |
|
|
|
ENABLE_VSYNC = os.getenv("ENABLE_VSYNC") == "1" |
|
|
|
ENABLE_VSYNC = os.getenv("ENABLE_VSYNC") == "1" |
|
|
|
DEBUG_FPS = os.getenv("DEBUG_FPS") == '1' |
|
|
|
DEBUG_FPS = os.getenv("DEBUG_FPS") == '1' |
|
|
|
STRICT_MODE = os.getenv("STRICT_MODE") == '1' |
|
|
|
STRICT_MODE = os.getenv("STRICT_MODE") == '1' |
|
|
|
|
|
|
|
SCALE = float(os.getenv("SCALE", "1.0")) |
|
|
|
|
|
|
|
|
|
|
|
DEFAULT_TEXT_SIZE = 60 |
|
|
|
DEFAULT_TEXT_SIZE = 60 |
|
|
|
DEFAULT_TEXT_COLOR = rl.WHITE |
|
|
|
DEFAULT_TEXT_COLOR = rl.WHITE |
|
|
@ -22,6 +23,7 @@ DEFAULT_TEXT_COLOR = rl.WHITE |
|
|
|
ASSETS_DIR = files("openpilot.selfdrive").joinpath("assets") |
|
|
|
ASSETS_DIR = files("openpilot.selfdrive").joinpath("assets") |
|
|
|
FONT_DIR = ASSETS_DIR.joinpath("fonts") |
|
|
|
FONT_DIR = ASSETS_DIR.joinpath("fonts") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FontWeight(IntEnum): |
|
|
|
class FontWeight(IntEnum): |
|
|
|
THIN = 0 |
|
|
|
THIN = 0 |
|
|
|
EXTRA_LIGHT = 1 |
|
|
|
EXTRA_LIGHT = 1 |
|
|
@ -39,6 +41,10 @@ class GuiApplication: |
|
|
|
self._fonts: dict[FontWeight, rl.Font] = {} |
|
|
|
self._fonts: dict[FontWeight, rl.Font] = {} |
|
|
|
self._width = width |
|
|
|
self._width = width |
|
|
|
self._height = height |
|
|
|
self._height = height |
|
|
|
|
|
|
|
self._scale = SCALE |
|
|
|
|
|
|
|
self._scaled_width = int(self._width * self._scale) |
|
|
|
|
|
|
|
self._scaled_height = int(self._height * self._scale) |
|
|
|
|
|
|
|
self._render_texture: rl.RenderTexture | None = None |
|
|
|
self._textures: dict[str, rl.Texture] = {} |
|
|
|
self._textures: dict[str, rl.Texture] = {} |
|
|
|
self._target_fps: int = DEFAULT_FPS |
|
|
|
self._target_fps: int = DEFAULT_FPS |
|
|
|
self._last_fps_log_time: float = time.monotonic() |
|
|
|
self._last_fps_log_time: float = time.monotonic() |
|
|
@ -62,14 +68,15 @@ class GuiApplication: |
|
|
|
flags |= rl.ConfigFlags.FLAG_VSYNC_HINT |
|
|
|
flags |= rl.ConfigFlags.FLAG_VSYNC_HINT |
|
|
|
rl.set_config_flags(flags) |
|
|
|
rl.set_config_flags(flags) |
|
|
|
|
|
|
|
|
|
|
|
rl.init_window(self._width, self._height, title) |
|
|
|
rl.init_window(self._scaled_width, self._scaled_height, title) |
|
|
|
|
|
|
|
if self._scale != 1.0: |
|
|
|
|
|
|
|
self._render_texture = rl.load_render_texture(self._width, self._height) |
|
|
|
rl.set_target_fps(fps) |
|
|
|
rl.set_target_fps(fps) |
|
|
|
|
|
|
|
|
|
|
|
self._target_fps = fps |
|
|
|
self._target_fps = fps |
|
|
|
self._set_styles() |
|
|
|
self._set_styles() |
|
|
|
self._load_fonts() |
|
|
|
self._load_fonts() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def texture(self, asset_path: str, width: int, height: int, alpha_premultiply=False, keep_aspect_ratio=True): |
|
|
|
def texture(self, asset_path: str, width: int, height: int, alpha_premultiply=False, keep_aspect_ratio=True): |
|
|
|
cache_key = f"{asset_path}_{width}_{height}_{alpha_premultiply}{keep_aspect_ratio}" |
|
|
|
cache_key = f"{asset_path}_{width}_{height}_{alpha_premultiply}{keep_aspect_ratio}" |
|
|
|
if cache_key in self._textures: |
|
|
|
if cache_key in self._textures: |
|
|
@ -80,7 +87,7 @@ class GuiApplication: |
|
|
|
self._textures[cache_key] = texture_obj |
|
|
|
self._textures[cache_key] = texture_obj |
|
|
|
return texture_obj |
|
|
|
return texture_obj |
|
|
|
|
|
|
|
|
|
|
|
def _load_texture_from_image(self, image_path: str, width: int, height: int, alpha_premultiply = False, keep_aspect_ratio=True): |
|
|
|
def _load_texture_from_image(self, image_path: str, width: int, height: int, alpha_premultiply=False, keep_aspect_ratio=True): |
|
|
|
"""Load and resize a texture, storing it for later automatic unloading.""" |
|
|
|
"""Load and resize a texture, storing it for later automatic unloading.""" |
|
|
|
image = rl.load_image(image_path) |
|
|
|
image = rl.load_image(image_path) |
|
|
|
|
|
|
|
|
|
|
@ -123,16 +130,32 @@ class GuiApplication: |
|
|
|
rl.unload_font(font) |
|
|
|
rl.unload_font(font) |
|
|
|
self._fonts = {} |
|
|
|
self._fonts = {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if self._render_texture is not None: |
|
|
|
|
|
|
|
rl.unload_render_texture(self._render_texture) |
|
|
|
|
|
|
|
self._render_texture = None |
|
|
|
|
|
|
|
|
|
|
|
rl.close_window() |
|
|
|
rl.close_window() |
|
|
|
|
|
|
|
|
|
|
|
def render(self): |
|
|
|
def render(self): |
|
|
|
try: |
|
|
|
try: |
|
|
|
while not (self._window_close_requested or rl.window_should_close()): |
|
|
|
while not (self._window_close_requested or rl.window_should_close()): |
|
|
|
rl.begin_drawing() |
|
|
|
if self._render_texture: |
|
|
|
rl.clear_background(rl.BLACK) |
|
|
|
rl.begin_texture_mode(self._render_texture) |
|
|
|
|
|
|
|
rl.clear_background(rl.BLACK) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
rl.begin_drawing() |
|
|
|
|
|
|
|
rl.clear_background(rl.BLACK) |
|
|
|
|
|
|
|
|
|
|
|
yield |
|
|
|
yield |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if self._render_texture: |
|
|
|
|
|
|
|
rl.end_texture_mode() |
|
|
|
|
|
|
|
rl.begin_drawing() |
|
|
|
|
|
|
|
rl.clear_background(rl.BLACK) |
|
|
|
|
|
|
|
src_rect = rl.Rectangle(0, 0, float(self._width), -float(self._height)) |
|
|
|
|
|
|
|
dst_rect = rl.Rectangle(0, 0, float(self._scaled_width), float(self._scaled_height)) |
|
|
|
|
|
|
|
rl.draw_texture_pro(self._render_texture.texture, src_rect, dst_rect, rl.Vector2(0, 0), 0.0, rl.WHITE) |
|
|
|
|
|
|
|
|
|
|
|
if DEBUG_FPS: |
|
|
|
if DEBUG_FPS: |
|
|
|
rl.draw_fps(10, 10) |
|
|
|
rl.draw_fps(10, 10) |
|
|
|
|
|
|
|
|
|
|
@ -141,7 +164,7 @@ class GuiApplication: |
|
|
|
except KeyboardInterrupt: |
|
|
|
except KeyboardInterrupt: |
|
|
|
pass |
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
def font(self, font_weight: FontWeight=FontWeight.NORMAL): |
|
|
|
def font(self, font_weight: FontWeight = FontWeight.NORMAL): |
|
|
|
return self._fonts[font_weight] |
|
|
|
return self._fonts[font_weight] |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
@ -163,7 +186,7 @@ class GuiApplication: |
|
|
|
"Inter-Bold.ttf", |
|
|
|
"Inter-Bold.ttf", |
|
|
|
"Inter-ExtraBold.ttf", |
|
|
|
"Inter-ExtraBold.ttf", |
|
|
|
"Inter-Black.ttf", |
|
|
|
"Inter-Black.ttf", |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
for index, font_file in enumerate(font_files): |
|
|
|
for index, font_file in enumerate(font_files): |
|
|
|
with as_file(FONT_DIR.joinpath(font_file)) as fspath: |
|
|
|
with as_file(FONT_DIR.joinpath(font_file)) as fspath: |
|
|
|