BigUI WIP: Add some graphics

This commit is contained in:
firestarsdog
2026-06-24 02:13:48 -04:00
parent f6b51e6742
commit 8c32f6d99d
4 changed files with 213 additions and 4 deletions
+31
View File
@@ -0,0 +1,31 @@
import sys
import os
import pyray as rl
# Add selfdrive's parent to path to support openpilot imports
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from selfdrive.ui.layouts.settings.starpilot.scribble import draw_custom_icon
def main():
rl.init_window(200, 200, "Icon Render")
rl.set_target_fps(60)
# Run for a few frames to make sure rendering is ready
for _ in range(10):
rl.begin_drawing()
rl.clear_background(rl.Color(15, 12, 30, 255)) # Dark background matching Driving Model tile
# Draw aicar icon centered
# x_c and y_c will be at x + 30*s, y + 30*s.
# Let's draw it at x=70, y=70, scale s=1.0. Centered at 100, 100.
draw_custom_icon("aicar", 70.0, 70.0, 1.0, rl.WHITE)
rl.end_drawing()
rl.take_screenshot("scratch/aicar_preview.png")
rl.close_window()
print("Screenshot saved to scratch/aicar_preview.png")
if __name__ == "__main__":
main()
@@ -3519,7 +3519,7 @@ class HubTile(AetherTile):
self.get_status = get_status
self.title = title
self.desc = desc
self.custom_icon_key = icon_key if icon_key in ("sound", "steering", "navigate", "system", "display", "vehicle") else None
self.custom_icon_key = icon_key if icon_key in ("sound", "steering", "navigate", "system", "display", "vehicle", "road", "aicar") else None
self._icon = None
self._font_title = gui_app.font(FontWeight.BOLD)
self._font_desc = gui_app.font(FontWeight.MEDIUM)
@@ -29,7 +29,7 @@ class StarPilotLayout(Widget):
{
"title": "Driving Controls",
"icon": "steering",
"buttons": [("DRIVING MODEL", "DRIVING_MODEL"), ("GAS / BRAKE", "LONGITUDINAL"), ("STEERING", "LATERAL")],
"buttons": [("DRIVING MODEL", "DRIVING_MODEL", "aicar"), ("GAS / BRAKE", "LONGITUDINAL", "road"), ("STEERING", "LATERAL", "steering")],
},
{
"title": "Map Data",
@@ -203,7 +203,13 @@ class StarPilotLayout(Widget):
cat = self.CATEGORIES[self._current_category_idx]
visible_buttons = cat["buttons"]
for label, panel_key in visible_buttons:
for button_info in visible_buttons:
if len(button_info) == 3:
label, panel_key, btn_icon = button_info
else:
label, panel_key = button_info
btn_icon = cat["icon"]
p_type = panel_type_map[panel_key]
def on_btn_click(p=p_type):
self._set_current_panel(p)
@@ -211,7 +217,7 @@ class StarPilotLayout(Widget):
tile = HubTile(
title=tr(label),
desc="",
icon_key=cat["icon"],
icon_key=btn_icon,
on_click=on_btn_click,
bg_color=cat.get("color")
)
@@ -219,6 +219,178 @@ def draw_custom_icon(key: str, x: float, y: float, s: float, color: rl.Color):
rl.draw_line_ex(rl.Vector2(x + 18.0 * s, y + 25.0 * s), rl.Vector2(x + 36.0 * s, y + 25.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x + 36.0 * s, y + 25.0 * s), rl.Vector2(x + 34.0 * s, y + 20.0 * s), 1.5 * s, color)
elif key == "road":
# Curvy Road: Vertical perspective road with dashed center line
x_c = x + 30.0 * s
y_c = y + 30.0 * s
def draw_cubic_bezier(p0: rl.Vector2, p1: rl.Vector2, p2: rl.Vector2, p3: rl.Vector2, thick: float):
segments = 64
for i in range(segments):
t1 = i / segments
t2 = (i + 1) / segments
t1_3 = (1 - t1)**3
t1_2_t = 3 * (1 - t1)**2 * t1
t_t1_2 = 3 * (1 - t1) * t1**2
t1_cube = t1**3
x1_val = t1_3 * p0.x + t1_2_t * p1.x + t_t1_2 * p2.x + t1_cube * p3.x
y1_val = t1_3 * p0.y + t1_2_t * p1.y + t_t1_2 * p2.y + t1_cube * p3.y
t2_3 = (1 - t2)**3
t2_2_t = 3 * (1 - t2)**2 * t2
t_t2_2 = 3 * (1 - t2) * t2**2
t2_cube = t2**3
x2_val = t2_3 * p0.x + t2_2_t * p1.x + t_t2_2 * p2.x + t2_cube * p3.x
y2_val = t2_3 * p0.y + t2_2_t * p1.y + t_t2_2 * p2.y + t2_cube * p3.y
rl.draw_line_ex(rl.Vector2(x1_val, y1_val), rl.Vector2(x2_val, y2_val), thick, color)
# Center reference points for S-curve
p0_c = rl.Vector2(x_c, y_c + 24.0 * s)
p1_c = rl.Vector2(x_c - 16.0 * s, y_c + 9.0 * s)
p2_c = rl.Vector2(x_c + 16.0 * s, y_c - 5.0 * s)
p3_c = rl.Vector2(x_c, y_c - 19.0 * s)
# Left edge points (widest at bottom, tapering at top)
p0_l = rl.Vector2(p0_c.x - 17.0 * s, p0_c.y)
p1_l = rl.Vector2(p1_c.x - 12.0 * s, p1_c.y)
p2_l = rl.Vector2(p2_c.x - 8.0 * s, p2_c.y)
p3_l = rl.Vector2(p3_c.x - 5.0 * s, p3_c.y)
draw_cubic_bezier(p0_l, p1_l, p2_l, p3_l, 3.0 * s)
# Right edge points (widest at bottom, tapering at top)
p0_r = rl.Vector2(p0_c.x + 17.0 * s, p0_c.y)
p1_r = rl.Vector2(p1_c.x + 12.0 * s, p1_c.y)
p2_r = rl.Vector2(p2_c.x + 8.0 * s, p2_c.y)
p3_r = rl.Vector2(p3_c.x + 5.0 * s, p3_c.y)
draw_cubic_bezier(p0_r, p1_r, p2_r, p3_r, 3.0 * s)
# Center dashed line
dash_count = 4
for i in range(dash_count):
t1 = (i + 0.15) / dash_count
t2 = (i + 0.65) / dash_count
t1_3 = (1 - t1)**3
t1_2_t = 3 * (1 - t1)**2 * t1
t_t1_2 = 3 * (1 - t1) * t1**2
t1_cube = t1**3
x1_val = t1_3 * p0_c.x + t1_2_t * p1_c.x + t_t1_2 * p2_c.x + t1_cube * p3_c.x
y1_val = t1_3 * p0_c.y + t1_2_t * p1_c.y + t_t1_2 * p2_c.y + t1_cube * p3_c.y
t2_3 = (1 - t2)**3
t2_2_t = 3 * (1 - t2)**2 * t2
t_t2_2 = 3 * (1 - t2) * t2**2
t2_cube = t2**3
x2_val = t2_3 * p0_c.x + t2_2_t * p1_c.x + t_t2_2 * p2_c.x + t2_cube * p3_c.x
y2_val = t2_3 * p0_c.y + t2_2_t * p1_c.y + t_t2_2 * p2_c.y + t2_cube * p3_c.y
rl.draw_line_ex(rl.Vector2(x1_val, y1_val), rl.Vector2(x2_val, y2_val), 2.5 * s, color)
elif key == "aicar":
# AI Car: Half car silhouette on the left (Sedan), circuit traces with contact pads on the right
x_c = x + 30.0 * s
y_c = y + 30.0 * s
def draw_pad(cx: float, cy: float, size: float):
half = size / 2.0
rl.draw_line_ex(rl.Vector2(cx - half, cy - half), rl.Vector2(cx + half, cy - half), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(cx + half, cy - half), rl.Vector2(cx + half, cy + half), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(cx + half, cy + half), rl.Vector2(cx - half, cy + half), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(cx - half, cy + half), rl.Vector2(cx - half, cy - half), 1.5 * s, color)
dot_half = size / 4.0
rl.draw_rectangle_rec(rl.Rectangle(cx - dot_half, cy - dot_half, size / 2.0, size / 2.0), color)
# 1. Soft Dashed Vertical Splitter (Blending/Transition Effect)
r = color.r if hasattr(color, "r") else color[0]
g = color.g if hasattr(color, "g") else color[1]
b = color.b if hasattr(color, "b") else color[2]
divider_color = rl.Color(r, g, b, 60) # ~24% opacity
dash_len = 1.0 * s
gap_len = 2.0 * s
curr_y = y_c - 16.0 * s
end_y = y_c + 12.0 * s
while curr_y < end_y:
rl.draw_line_ex(rl.Vector2(x_c, curr_y), rl.Vector2(x_c, min(curr_y + dash_len, end_y)), 1.5 * s, divider_color)
curr_y += dash_len + gap_len
# 2. Right Side (AI Circuit Traces & Pads)
# Trace 1 (Top - Aligned with roofline)
rl.draw_line_ex(rl.Vector2(x_c, y_c - 16.0 * s), rl.Vector2(x_c + 8.0 * s, y_c - 16.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 8.0 * s, y_c - 16.0 * s), rl.Vector2(x_c + 14.0 * s, y_c - 20.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 14.0 * s, y_c - 20.0 * s), rl.Vector2(x_c + 22.0 * s, y_c - 20.0 * s), 1.5 * s, color)
draw_pad(x_c + 24.0 * s, y_c - 20.0 * s, 3.5 * s)
# Trace 2 (Aligned with window bottom / beltline)
rl.draw_line_ex(rl.Vector2(x_c, y_c - 5.0 * s), rl.Vector2(x_c + 8.0 * s, y_c - 5.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 8.0 * s, y_c - 5.0 * s), rl.Vector2(x_c + 13.0 * s, y_c - 9.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 13.0 * s, y_c - 9.0 * s), rl.Vector2(x_c + 18.0 * s, y_c - 9.0 * s), 1.5 * s, color)
draw_pad(x_c + 20.0 * s, y_c - 9.0 * s, 3.5 * s)
# Trace 3 (Forked - Centered on door)
rl.draw_line_ex(rl.Vector2(x_c, y_c + 1.0 * s), rl.Vector2(x_c + 6.0 * s, y_c + 1.0 * s), 1.5 * s, color)
# Fork 3A (Up)
rl.draw_line_ex(rl.Vector2(x_c + 6.0 * s, y_c + 1.0 * s), rl.Vector2(x_c + 10.0 * s, y_c - 2.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 10.0 * s, y_c - 2.0 * s), rl.Vector2(x_c + 16.0 * s, y_c - 2.0 * s), 1.5 * s, color)
draw_pad(x_c + 18.0 * s, y_c - 2.0 * s, 3.5 * s)
# Fork 3B (Down)
rl.draw_line_ex(rl.Vector2(x_c + 6.0 * s, y_c + 1.0 * s), rl.Vector2(x_c + 10.0 * s, y_c + 4.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 10.0 * s, y_c + 4.0 * s), rl.Vector2(x_c + 16.0 * s, y_c + 4.0 * s), 1.5 * s, color)
draw_pad(x_c + 18.0 * s, y_c + 4.0 * s, 3.5 * s)
# Trace 4 (Lower door)
rl.draw_line_ex(rl.Vector2(x_c, y_c + 7.0 * s), rl.Vector2(x_c + 7.0 * s, y_c + 7.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 7.0 * s, y_c + 7.0 * s), rl.Vector2(x_c + 11.0 * s, y_c + 10.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 11.0 * s, y_c + 10.0 * s), rl.Vector2(x_c + 15.0 * s, y_c + 10.0 * s), 1.5 * s, color)
draw_pad(x_c + 17.0 * s, y_c + 10.0 * s, 3.5 * s)
# Trace 5 (Bottom - Aligned with rocker panel)
rl.draw_line_ex(rl.Vector2(x_c, y_c + 12.0 * s), rl.Vector2(x_c + 8.0 * s, y_c + 12.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 8.0 * s, y_c + 12.0 * s), rl.Vector2(x_c + 14.0 * s, y_c + 18.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c + 14.0 * s, y_c + 18.0 * s), rl.Vector2(x_c + 22.0 * s, y_c + 18.0 * s), 1.5 * s, color)
draw_pad(x_c + 24.0 * s, y_c + 18.0 * s, 3.5 * s)
# 3. Left Side (Car Front silhouette - Sleek modern profile with long sweeping windshield)
# Roof & Windshield (continuous Bezier curve profile)
p0_roof = rl.Vector2(x_c, y_c - 16.0 * s)
p1_roof = rl.Vector2(x_c - 12.0 * s, y_c - 16.0 * s)
p2_roof = rl.Vector2(x_c - 22.0 * s, y_c - 5.0 * s)
draw_bezier(p0_roof, p1_roof, p2_roof, 2.0 * s)
# Hood (short, streamlined)
p0_hood = rl.Vector2(x_c - 22.0 * s, y_c - 5.0 * s)
p1_hood = rl.Vector2(x_c - 25.0 * s, y_c - 4.5 * s)
p2_hood = rl.Vector2(x_c - 28.0 * s, y_c - 2.5 * s)
draw_bezier(p0_hood, p1_hood, p2_hood, 2.0 * s)
# Nose & Bumper Curve
p0_nose = rl.Vector2(x_c - 28.0 * s, y_c - 2.5 * s)
p1_nose = rl.Vector2(x_c - 31.0 * s, y_c + 1.0 * s)
p2_nose = rl.Vector2(x_c - 28.0 * s, y_c + 12.0 * s)
draw_bezier(p0_nose, p1_nose, p2_nose, 2.0 * s)
# Wheel Arch
draw_ellipse_arc(x_c - 21.0 * s, y_c + 12.0 * s, 7.0 * s, 7.0 * s, 0.0, 180.0, 360.0, 2.0 * s)
# Underbody / Rocker panel (aligned with Trace 5)
rl.draw_line_ex(rl.Vector2(x_c - 14.0 * s, y_c + 12.0 * s), rl.Vector2(x_c, y_c + 12.0 * s), 2.0 * s, color)
# Wheel (hollow ring matching the arch)
rl.draw_ring(rl.Vector2(x_c - 21.0 * s, y_c + 12.0 * s), 3.5 * s, 5.0 * s, 0.0, 360.0, 24, color)
# Side Window Details (Parallel sloped wedge, open to the dashed divider at the rear to blend perfectly)
p0_win = rl.Vector2(x_c, y_c - 13.0 * s)
p1_win = rl.Vector2(x_c - 10.0 * s, y_c - 13.0 * s)
p2_win = rl.Vector2(x_c - 18.0 * s, y_c - 5.0 * s)
draw_bezier(p0_win, p1_win, p2_win, 1.5 * s)
rl.draw_line_ex(rl.Vector2(x_c - 18.0 * s, y_c - 5.0 * s), rl.Vector2(x_c, y_c - 5.0 * s), 1.5 * s, color)
rl.draw_line_ex(rl.Vector2(x_c - 9.0 * s, y_c - 11.4 * s), rl.Vector2(x_c - 9.0 * s, y_c - 5.0 * s), 1.5 * s, color)
elif key == "first_aid":
# First Aid Kit Symbol
x_c = x + 30.0 * s