diff --git a/common/params.cc b/common/params.cc index c4ce1f7d6a..7b7ab041e3 100644 --- a/common/params.cc +++ b/common/params.cc @@ -245,6 +245,7 @@ std::unordered_map keys = { {"FastTakeOff", PERSISTENT}, {"AccelPersonality", PERSISTENT}, {"ToyotaDriveMode", PERSISTENT}, + {"RainbowMode", PERSISTENT}, }; } // namespace diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 82461b4ae1..754251fa7c 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -65,6 +65,12 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { tr("Enable Toyota Drive Mode Button"), tr("Sunnypilot will link the Acceleration Personality to the car's physical drive mode selector.\nReboot Required."), "../assets/offroad/icon_blank.png", + }, + { + "RainbowMode", + tr("Enable Tesla Rainbow Mode"), + tr("....."), + "../assets/offroad/icon_blank.png", }, { "DisengageOnAccelerator", diff --git a/selfdrive/ui/qt/onroad/model.cc b/selfdrive/ui/qt/onroad/model.cc index 402ad789d4..fc100a8ad9 100644 --- a/selfdrive/ui/qt/onroad/model.cc +++ b/selfdrive/ui/qt/onroad/model.cc @@ -111,12 +111,34 @@ void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reade auto &sm = *(s->sm); float v_ego = sm["carState"].getCarState().getVEgo(); + bool rainbow = Params().getBool("RainbowMode"); - // Get the current time in milliseconds for dynamic effect (speed of rainbow movement) - auto now = std::chrono::steady_clock::now().time_since_epoch(); - float time_offset = std::chrono::duration_cast(now).count() / 1000.0f; // seconds + // Get the current time in seconds for dynamic effect (speed of rainbow movement) + float time_offset = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count() / 1000.0f; - if (experimental_mode) { + if (rainbow) { // Rainbow Mode + const int max_len = track_vertices.length(); + bg.setSpread(QGradient::PadSpread); // Pad for a smooth gradient fade + + for (int i = 0; i < max_len; i += 2) { // Skip every other point for performance + if (track_vertices[i].y() < 0 || track_vertices[i].y() > height) continue; + + float lin_grad_point = (height - track_vertices[i].y()) / height; + + // Use easing for smoother color transitions + float eased_point = pow(lin_grad_point, 1.5f); // Ease-in effect + + // Dynamic hue with subtle, smooth animation + float path_hue = fmod(eased_point * 360.0 + (v_ego * 20.0) + (time_offset * 100.0), 360.0); + + // Smooth alpha transition with longer fade + float alpha = util::map_val(eased_point, 0.2f, 0.75f, 0.8f, 0.0f); + + // Use soft lightness for a premium feel + bg.setColorAt(eased_point, QColor::fromHslF(path_hue / 360.0, 1.0f, 0.55f, alpha)); + } + } else if (experimental_mode) { // The first half of track_vertices are the points for the right side of the path const auto &acceleration = model.getAcceleration().getX(); const int max_len = std::min(track_vertices.length() / 2, acceleration.size()); @@ -143,30 +165,6 @@ void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reade i += (i + 2) < max_len ? 1 : 0; } - } else if (false) { // Rainbow Mode - const int max_len = track_vertices.length(); - bg.setSpread(QGradient::RepeatSpread); // Repeat gradient for continuous effect - - for (int i = 0; i < max_len; i += 2) { // Skip every other point for performance - // Skip points out of the visible frame - if (track_vertices[i].y() < 0 || track_vertices[i].y() > height) continue; - - // Normalize for gradient positioning - float lin_grad_point = (height - track_vertices[i].y()) / height; - - // Dynamic hue based on speed (v_ego) and time offset for smooth movement - float path_hue = fmod(lin_grad_point * 360.0 + (v_ego * 30.0) + (time_offset * 120.0), 360.0); - - // Define constant saturation and lightness for vivid colors - float saturation = 1.0f; - float lightness = 0.5f; - - // Adjust alpha fading for smoother transitions - float alpha = util::map_val(lin_grad_point, 0.75f / 2.f, 0.75f, 0.6f, 0.0f); - - // Set color at the calculated gradient point - bg.setColorAt(lin_grad_point, QColor::fromHslF(path_hue / 360.0, saturation, lightness, alpha)); - } } else { updatePathGradient(bg); }