diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index b9d4293738..ba1441170b 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -18,6 +18,7 @@ STRICT_MODE = os.getenv("STRICT_MODE") == '1' DEFAULT_TEXT_SIZE = 60 DEFAULT_TEXT_COLOR = rl.Color(200, 200, 200, 255) +ASSETS_DIR = os.path.join(BASEDIR, "selfdrive/assets") FONT_DIR = os.path.join(BASEDIR, "selfdrive/assets/fonts") @@ -37,7 +38,7 @@ class GuiApplication: self._fonts: dict[FontWeight, rl.Font] = {} self._width = width self._height = height - self._textures: list[rl.Texture] = [] + self._textures: dict[str, rl.Texture] = {} self._target_fps: int = DEFAULT_FPS self._last_fps_log_time: float = time.monotonic() self._window_close_requested = False @@ -67,28 +68,61 @@ class GuiApplication: self._set_styles() self._load_fonts() - def load_texture_from_image(self, file_name: str, width: int, height: int, alpha_premultiply = False): + + 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}" + if cache_key in self._textures: + return self._textures[cache_key] + + texture_obj = self._load_texture_from_image(os.path.join(ASSETS_DIR, asset_path), width, height, alpha_premultiply, keep_aspect_ratio) + self._textures[cache_key] = 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): """Load and resize a texture, storing it for later automatic unloading.""" - image = rl.load_image(file_name) + if image_path.endswith('.svg'): + image = self._load_image_from_svg(image_path) + else: + image = rl.load_image(image_path) + if alpha_premultiply: rl.image_alpha_premultiply(image) - rl.image_resize(image, width, height) + + # Resize with aspect ratio preservation if requested + if keep_aspect_ratio: + orig_width = image.width + orig_height = image.height + + scale_width = width / orig_width + scale_height = height / orig_height + + # Calculate new dimensions + scale = min(scale_width, scale_height) + new_width = int(orig_width * scale) + new_height = int(orig_height * scale) + + rl.image_resize(image, new_width, new_height) + else: + rl.image_resize(image, width, height) + texture = rl.load_texture_from_image(image) # Set texture filtering to smooth the result rl.set_texture_filter(texture, rl.TextureFilter.TEXTURE_FILTER_BILINEAR) rl.unload_image(image) - - self._textures.append(texture) return texture + def _load_image_from_svg(self, svg_path: str): + # TODO: Implement SVG loading + assert(0) + def close(self): if not rl.is_window_ready(): return - for texture in self._textures: + for texture in self._textures.values(): rl.unload_texture(texture) - self._textures = [] + self._textures = {} for font in self._fonts.values(): rl.unload_font(font) diff --git a/system/ui/spinner.py b/system/ui/spinner.py index 119bdba3e7..93bce3887e 100755 --- a/system/ui/spinner.py +++ b/system/ui/spinner.py @@ -1,10 +1,8 @@ #!/usr/bin/env python3 import pyray as rl -import os import threading import time -from openpilot.common.basedir import BASEDIR from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.window import BaseWindow from openpilot.system.ui.text import wrap_text @@ -26,9 +24,8 @@ def clamp(value, min_value, max_value): class SpinnerRenderer: def __init__(self): - self._comma_texture = gui_app.load_texture_from_image(os.path.join(BASEDIR, "selfdrive/assets/img_spinner_comma.png"), TEXTURE_SIZE, TEXTURE_SIZE) - self._spinner_texture = gui_app.load_texture_from_image(os.path.join(BASEDIR, "selfdrive/assets/img_spinner_track.png"), TEXTURE_SIZE, TEXTURE_SIZE, - alpha_premultiply=True) + self._comma_texture = gui_app.texture("img_spinner_comma.png", TEXTURE_SIZE, TEXTURE_SIZE) + self._spinner_texture = gui_app.texture("img_spinner_track.png", TEXTURE_SIZE, TEXTURE_SIZE, alpha_premultiply=True) self._rotation = 0.0 self._progress: int | None = None self._wrapped_lines: list[str] = []