From 88857e80285b2a72428818b208023d1d6c8ad5c7 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <github@thinkyhead.com>
Date: Fri, 13 Oct 2017 16:16:32 -0500
Subject: [PATCH] Move fade_scaling_factor_for_z to Planner

---
 Marlin/Marlin_main.cpp         | 134 ++++++++++++++-----------------
 Marlin/configuration_store.cpp | 124 +++++++++++++++--------------
 Marlin/mesh_bed_leveling.cpp   |   4 +-
 Marlin/mesh_bed_leveling.h     |  13 +--
 Marlin/planner.cpp             | 139 ++++++++++++++-------------------
 Marlin/planner.h               |  71 +++++++++++++----
 Marlin/ubl.cpp                 |  11 +--
 Marlin/ubl.h                   |  27 -------
 Marlin/ubl_G29.cpp             |   2 +-
 Marlin/ubl_motion.cpp          |  36 ++++-----
 Marlin/ultralcd.cpp            |   7 +-
 Marlin/ultralcd_impl_HD44780.h |   2 +-
 12 files changed, 266 insertions(+), 304 deletions(-)

diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index dcfd6881919..b28ba0b8910 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -544,14 +544,14 @@ static uint8_t target_extruder;
 #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
   #if ENABLED(DELTA)
     #define ADJUST_DELTA(V) \
-      if (planner.abl_enabled) { \
+      if (planner.leveling_active) { \
         const float zadj = bilinear_z_offset(V); \
         delta[A_AXIS] += zadj; \
         delta[B_AXIS] += zadj; \
         delta[C_AXIS] += zadj; \
       }
   #else
-    #define ADJUST_DELTA(V) if (planner.abl_enabled) { delta[Z_AXIS] += bilinear_z_offset(V); }
+    #define ADJUST_DELTA(V) if (planner.leveling_active) { delta[Z_AXIS] += bilinear_z_offset(V); }
   #endif
 #elif IS_KINEMATIC
   #define ADJUST_DELTA(V) NOOP
@@ -2460,7 +2460,7 @@ static void clean_up_after_endstop_or_probe_move() {
   bool leveling_is_valid() {
     return
       #if ENABLED(MESH_BED_LEVELING)
-        mbl.has_mesh()
+        mbl.has_mesh
       #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
         !!bilinear_grid_spacing[X_AXIS]
       #elif ENABLED(AUTO_BED_LEVELING_UBL)
@@ -2486,7 +2486,7 @@ static void clean_up_after_endstop_or_probe_move() {
       constexpr bool can_change = true;
     #endif
 
-    if (can_change && enable != LEVELING_IS_ACTIVE()) {
+    if (can_change && enable != planner.leveling_active) {
 
       #if ENABLED(MESH_BED_LEVELING)
 
@@ -2494,23 +2494,23 @@ static void clean_up_after_endstop_or_probe_move() {
           planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
 
         const bool enabling = enable && leveling_is_valid();
-        mbl.set_active(enabling);
+        planner.leveling_active = enabling;
         if (enabling) planner.unapply_leveling(current_position);
 
       #elif ENABLED(AUTO_BED_LEVELING_UBL)
         #if PLANNER_LEVELING
-          if (ubl.state.active) {                       // leveling from on to off
+          if (planner.leveling_active) {                       // leveling from on to off
             // change unleveled current_position to physical current_position without moving steppers.
             planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
-            ubl.state.active = false;                   // disable only AFTER calling apply_leveling
+            planner.leveling_active = false;                   // disable only AFTER calling apply_leveling
           }
           else {                                        // leveling from off to on
-            ubl.state.active = true;                    // enable BEFORE calling unapply_leveling, otherwise ignored
+            planner.leveling_active = true;                    // enable BEFORE calling unapply_leveling, otherwise ignored
             // change physical current_position to unleveled current_position without moving steppers.
             planner.unapply_leveling(current_position);
           }
         #else
-          ubl.state.active = enable;                    // just flip the bit, current_position will be wrong until next move.
+          planner.leveling_active = enable;                    // just flip the bit, current_position will be wrong until next move.
         #endif
 
       #else // ABL
@@ -2522,7 +2522,7 @@ static void clean_up_after_endstop_or_probe_move() {
         #endif
 
         // Enable or disable leveling compensation in the planner
-        planner.abl_enabled = enable;
+        planner.leveling_active = enable;
 
         if (!enable)
           // When disabling just get the current position from the steppers.
@@ -2547,23 +2547,18 @@ static void clean_up_after_endstop_or_probe_move() {
 
     void set_z_fade_height(const float zfh) {
 
-      const bool level_active = LEVELING_IS_ACTIVE();
+      const bool level_active = planner.leveling_active;
 
       #if ENABLED(AUTO_BED_LEVELING_UBL)
+        if (level_active) set_bed_leveling_enabled(false);  // turn off before changing fade height for proper apply/unapply leveling to maintain current_position
+      #endif
 
-        if (level_active)
-          set_bed_leveling_enabled(false);  // turn off before changing fade height for proper apply/unapply leveling to maintain current_position
-        planner.z_fade_height = zfh;
-        planner.inverse_z_fade_height = RECIPROCAL(zfh);
-        if (level_active)
+      planner.set_z_fade_height(zfh);
+
+      if (level_active) {
+        #if ENABLED(AUTO_BED_LEVELING_UBL)
           set_bed_leveling_enabled(true);  // turn back on after changing fade height
-
-      #else
-
-        planner.z_fade_height = zfh;
-        planner.inverse_z_fade_height = RECIPROCAL(zfh);
-
-        if (level_active) {
+        #else
           set_current_from_steppers_for_axis(
             #if ABL_PLANAR
               ALL_AXES
@@ -2571,8 +2566,8 @@ static void clean_up_after_endstop_or_probe_move() {
               Z_AXIS
             #endif
           );
-        }
-      #endif
+        #endif
+      }
     }
 
   #endif // LEVELING_FADE_HEIGHT
@@ -2585,7 +2580,7 @@ static void clean_up_after_endstop_or_probe_move() {
     #if ENABLED(MESH_BED_LEVELING)
       if (leveling_is_valid()) {
         mbl.reset();
-        mbl.set_has_mesh(false);
+        mbl.has_mesh = false;
       }
     #else
       #if ENABLED(DEBUG_LEVELING_FEATURE)
@@ -3759,7 +3754,7 @@ inline void gcode_G4() {
       #elif ENABLED(AUTO_BED_LEVELING_UBL)
         SERIAL_ECHOPGM("UBL");
       #endif
-      if (LEVELING_IS_ACTIVE()) {
+      if (planner.leveling_active) {
         SERIAL_ECHOLNPGM(" (enabled)");
         #if ABL_PLANAR
           const float diff[XYZ] = {
@@ -3790,7 +3785,7 @@ inline void gcode_G4() {
     #elif ENABLED(MESH_BED_LEVELING)
 
       SERIAL_ECHOPGM("Mesh Bed Leveling");
-      if (LEVELING_IS_ACTIVE()) {
+      if (planner.leveling_active) {
         float lz = current_position[Z_AXIS];
         planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], lz);
         SERIAL_ECHOLNPGM(" (enabled)");
@@ -3959,7 +3954,7 @@ inline void gcode_G28(const bool always_home_all) {
   // Disable the leveling matrix before homing
   #if HAS_LEVELING
     #if ENABLED(AUTO_BED_LEVELING_UBL)
-      const bool ubl_state_at_entry = LEVELING_IS_ACTIVE();
+      const bool ubl_state_at_entry = planner.leveling_active;
     #endif
     set_bed_leveling_enabled(false);
   #endif
@@ -4199,7 +4194,7 @@ void home_all_axes() { gcode_G28(true); }
   }
 
   void mesh_probing_done() {
-    mbl.set_has_mesh(true);
+    mbl.has_mesh = true;
     home_all_axes();
     set_bed_leveling_enabled(true);
     #if ENABLED(MESH_G28_REST_ORIGIN)
@@ -4249,7 +4244,7 @@ void home_all_axes() { gcode_G28(true); }
     switch (state) {
       case MeshReport:
         if (leveling_is_valid()) {
-          SERIAL_PROTOCOLLNPAIR("State: ", LEVELING_IS_ACTIVE() ? MSG_ON : MSG_OFF);
+          SERIAL_PROTOCOLLNPAIR("State: ", planner.leveling_active ? MSG_ON : MSG_OFF);
           mbl_mesh_report();
         }
         else
@@ -4568,7 +4563,7 @@ void home_all_axes() { gcode_G28(true); }
         abl_probe_index = -1;
       #endif
 
-      abl_should_enable = LEVELING_IS_ACTIVE();
+      abl_should_enable = planner.leveling_active;
 
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
 
@@ -4708,7 +4703,7 @@ void home_all_axes() { gcode_G28(true); }
       stepper.synchronize();
 
       // Disable auto bed leveling during G29
-      planner.abl_enabled = false;
+      planner.leveling_active = false;
 
       if (!dryrun) {
         // Re-orient the current position without leveling
@@ -4722,7 +4717,7 @@ void home_all_axes() { gcode_G28(true); }
       #if HAS_BED_PROBE
         // Deploy the probe. Probe will raise if needed.
         if (DEPLOY_PROBE()) {
-          planner.abl_enabled = abl_should_enable;
+          planner.leveling_active = abl_should_enable;
           return;
         }
       #endif
@@ -4741,7 +4736,7 @@ void home_all_axes() { gcode_G28(true); }
         ) {
           if (dryrun) {
             // Before reset bed level, re-enable to correct the position
-            planner.abl_enabled = abl_should_enable;
+            planner.leveling_active = abl_should_enable;
           }
           // Reset grid to 0.0 or "not probed". (Also disables ABL)
           reset_bed_level();
@@ -4786,7 +4781,7 @@ void home_all_axes() { gcode_G28(true); }
         #if HAS_SOFTWARE_ENDSTOPS
           soft_endstops_enabled = enable_soft_endstops;
         #endif
-        planner.abl_enabled = abl_should_enable;
+        planner.leveling_active = abl_should_enable;
         g29_in_progress = false;
         #if ENABLED(LCD_BED_LEVELING)
           lcd_wait_for_move = false;
@@ -4987,7 +4982,7 @@ void home_all_axes() { gcode_G28(true); }
             measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
 
             if (isnan(measured_z)) {
-              planner.abl_enabled = abl_should_enable;
+              planner.leveling_active = abl_should_enable;
               break;
             }
 
@@ -5023,7 +5018,7 @@ void home_all_axes() { gcode_G28(true); }
           yProbe = LOGICAL_Y_POSITION(points[i].y);
           measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
           if (isnan(measured_z)) {
-            planner.abl_enabled = abl_should_enable;
+            planner.leveling_active = abl_should_enable;
             break;
           }
           points[i].z = measured_z;
@@ -5046,7 +5041,7 @@ void home_all_axes() { gcode_G28(true); }
 
       // Raise to _Z_CLEARANCE_DEPLOY_PROBE. Stow the probe.
       if (STOW_PROBE()) {
-        planner.abl_enabled = abl_should_enable;
+        planner.leveling_active = abl_should_enable;
         measured_z = NAN;
       }
     }
@@ -5214,9 +5209,9 @@ void home_all_axes() { gcode_G28(true); }
           float converted[XYZ];
           COPY(converted, current_position);
 
-          planner.abl_enabled = true;
+          planner.leveling_active = true;
           planner.unapply_leveling(converted); // use conversion machinery
-          planner.abl_enabled = false;
+          planner.leveling_active = false;
 
           // Use the last measured distance to the bed, if possible
           if ( NEAR(current_position[X_AXIS], xProbe - (X_PROBE_OFFSET_FROM_EXTRUDER))
@@ -5268,7 +5263,7 @@ void home_all_axes() { gcode_G28(true); }
       #endif
 
       // Auto Bed Leveling is complete! Enable if possible.
-      planner.abl_enabled = dryrun ? abl_should_enable : true;
+      planner.leveling_active = dryrun ? abl_should_enable : true;
     } // !isnan(measured_z)
 
     // Restore state after probing
@@ -5282,7 +5277,7 @@ void home_all_axes() { gcode_G28(true); }
 
     KEEPALIVE_STATE(IN_HANDLER);
 
-    if (planner.abl_enabled)
+    if (planner.leveling_active)
       SYNC_PLAN_POSITION_KINEMATIC();
   }
 
@@ -7065,7 +7060,7 @@ inline void gcode_M42() {
     // Disable bed level correction in M48 because we want the raw data when we probe
 
     #if HAS_LEVELING
-      const bool was_enabled = LEVELING_IS_ACTIVE();
+      const bool was_enabled = planner.leveling_active;
       set_bed_leveling_enabled(false);
     #endif
 
@@ -9401,7 +9396,7 @@ void quickstop_stepper() {
       if (parser.seen('Z')) set_z_fade_height(parser.value_linear_units());
     #endif
 
-    const bool new_status = LEVELING_IS_ACTIVE();
+    const bool new_status = planner.leveling_active;
 
     if (to_enable && !new_status) {
       SERIAL_ERROR_START();
@@ -9632,7 +9627,7 @@ inline void gcode_M502() {
       #endif
 
       #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
-        if (!no_babystep && LEVELING_IS_ACTIVE())
+        if (!no_babystep && planner.leveling_active)
           thermalManager.babystep_axis(Z_AXIS, -LROUND(diff * planner.axis_steps_per_mm[Z_AXIS]));
       #else
         UNUSED(no_babystep);
@@ -10679,7 +10674,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
 
             #if ENABLED(MESH_BED_LEVELING)
 
-              if (LEVELING_IS_ACTIVE()) {
+              if (planner.leveling_active) {
                 #if ENABLED(DEBUG_LEVELING_FEATURE)
                   if (DEBUGGING(LEVELING)) SERIAL_ECHOPAIR("Z before MBL: ", current_position[Z_AXIS]);
                 #endif
@@ -12377,39 +12372,28 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
    * Prepare a linear move in a Cartesian setup.
    * If Mesh Bed Leveling is enabled, perform a mesh move.
    *
-   * Returns true if the caller didn't update current_position.
+   * Returns true if current_position[] was set to destination[]
    */
   inline bool prepare_move_to_destination_cartesian() {
-    #if ENABLED(AUTO_BED_LEVELING_UBL)
+    if (current_position[X_AXIS] != destination[X_AXIS] || current_position[Y_AXIS] != destination[Y_AXIS]) {
       const float fr_scaled = MMS_SCALED(feedrate_mm_s);
-      if (ubl.state.active) { // direct use of ubl.state.active for speed
-        ubl.line_to_destination_cartesian(fr_scaled, active_extruder);
-        return true;
-      }
-      else
-        line_to_destination(fr_scaled);
-    #else
-      // Do not use feedrate_percentage for E or Z only moves
-      if (current_position[X_AXIS] == destination[X_AXIS] && current_position[Y_AXIS] == destination[Y_AXIS])
-        line_to_destination();
-      else {
-        const float fr_scaled = MMS_SCALED(feedrate_mm_s);
-        #if ENABLED(MESH_BED_LEVELING)
-          if (mbl.active()) { // direct used of mbl.active() for speed
+      #if HAS_LEVELING
+        if (planner.leveling_active) {
+          #if ENABLED(AUTO_BED_LEVELING_UBL)
+            ubl.line_to_destination_cartesian(fr_scaled, active_extruder);
+          #elif ENABLED(MESH_BED_LEVELING)
             mesh_line_to_destination(fr_scaled);
-            return true;
-          }
-          else
-        #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
-          if (planner.abl_enabled) { // direct use of abl_enabled for speed
+          #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
             bilinear_line_to_destination(fr_scaled);
-            return true;
-          }
-          else
-        #endif
-            line_to_destination(fr_scaled);
-      }
-    #endif
+          #endif
+          return true;
+        }
+      #endif // HAS_LEVELING
+      line_to_destination(fr_scaled);
+    }
+    else
+      line_to_destination();
+
     return false;
   }
 
diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp
index 706f679ea99..4db7f0da61f 100644
--- a/Marlin/configuration_store.cpp
+++ b/Marlin/configuration_store.cpp
@@ -68,7 +68,7 @@
  *  219            z_fade_height                    (float)
  *
  * MESH_BED_LEVELING:                               43 bytes
- *  223  M420 S    from mbl.status                  (bool)
+ *  223  M420 S    planner.leveling_active          (bool)
  *  224            mbl.z_offset                     (float)
  *  228            GRID_MAX_POINTS_X                (uint8_t)
  *  229            GRID_MAX_POINTS_Y                (uint8_t)
@@ -88,7 +88,7 @@
  *  316            z_values[][]                     (float x9, up to float x256) +988
  *
  * AUTO_BED_LEVELING_UBL:                           6 bytes
- *  324  G29 A     ubl.state.active                 (bool)
+ *  324  G29 A     planner.leveling_active          (bool)
  *  325  G29 S     ubl.state.storage_slot           (int8_t)
  *
  * DELTA:                                           48 bytes
@@ -204,6 +204,10 @@ MarlinSettings settings;
   extern void refresh_bed_level();
 #endif
 
+#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+  float new_z_fade_height;
+#endif
+
 /**
  * Post-process after Retrieve or Reset
  */
@@ -233,7 +237,7 @@ void MarlinSettings::postprocess() {
   #endif
 
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-    set_z_fade_height(planner.z_fade_height);
+    set_z_fade_height(new_z_fade_height);
   #endif
 
   #if HAS_BED_PROBE
@@ -372,7 +376,7 @@ void MarlinSettings::postprocess() {
         sizeof(mbl.z_values) == GRID_MAX_POINTS * sizeof(mbl.z_values[0][0]),
         "MBL Z array is the wrong size."
       );
-      const bool leveling_is_on = TEST(mbl.status, MBL_STATUS_HAS_MESH_BIT);
+      const bool leveling_is_on = mbl.has_mesh;
       const uint8_t mesh_num_x = GRID_MAX_POINTS_X, mesh_num_y = GRID_MAX_POINTS_Y;
       EEPROM_WRITE(leveling_is_on);
       EEPROM_WRITE(mbl.z_offset);
@@ -435,7 +439,7 @@ void MarlinSettings::postprocess() {
     #endif // AUTO_BED_LEVELING_BILINEAR
 
     #if ENABLED(AUTO_BED_LEVELING_UBL)
-      EEPROM_WRITE(ubl.state.active);
+      EEPROM_WRITE(planner.leveling_active);
       EEPROM_WRITE(ubl.state.storage_slot);
     #else
       const bool ubl_active = false;
@@ -751,7 +755,7 @@ void MarlinSettings::postprocess() {
       //
 
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        EEPROM_READ(planner.z_fade_height);
+        EEPROM_READ(new_z_fade_height);
       #else
         EEPROM_READ(dummy);
       #endif
@@ -768,7 +772,7 @@ void MarlinSettings::postprocess() {
       EEPROM_READ(mesh_num_y);
 
       #if ENABLED(MESH_BED_LEVELING)
-        mbl.status = leveling_is_on ? _BV(MBL_STATUS_HAS_MESH_BIT) : 0;
+        mbl.has_mesh = leveling_is_on;
         mbl.z_offset = dummy;
         if (mesh_num_x == GRID_MAX_POINTS_X && mesh_num_y == GRID_MAX_POINTS_Y) {
           // EEPROM data fits the current mesh
@@ -824,7 +828,7 @@ void MarlinSettings::postprocess() {
         }
 
       #if ENABLED(AUTO_BED_LEVELING_UBL)
-        EEPROM_READ(ubl.state.active);
+        EEPROM_READ(planner.leveling_active);
         EEPROM_READ(ubl.state.storage_slot);
       #else
         uint8_t dummyui8;
@@ -1186,7 +1190,7 @@ void MarlinSettings::reset() {
   planner.max_jerk[E_AXIS] = DEFAULT_EJERK;
 
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-    planner.z_fade_height = 0.0;
+    new_z_fade_height = 10.0;
   #endif
 
   #if HAS_HOME_OFFSET
@@ -1563,65 +1567,71 @@ void MarlinSettings::reset() {
       }
     #endif
 
-    #if ENABLED(MESH_BED_LEVELING)
+    /**
+     * Bed Leveling
+     */
+    #if HAS_LEVELING
 
-      if (!forReplay) {
-        CONFIG_ECHO_START;
-        SERIAL_ECHOLNPGM("Mesh Bed Leveling:");
-      }
-      CONFIG_ECHO_START;
-      SERIAL_ECHOPAIR("  M420 S", leveling_is_valid() ? 1 : 0);
-      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.z_fade_height));
-      #endif
-      SERIAL_EOL();
-      for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
-        for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
+      #if ENABLED(MESH_BED_LEVELING)
+
+        if (!forReplay) {
           CONFIG_ECHO_START;
-          SERIAL_ECHOPAIR("  G29 S3 X", (int)px + 1);
-          SERIAL_ECHOPAIR(" Y", (int)py + 1);
-          SERIAL_ECHOPGM(" Z");
-          SERIAL_PROTOCOL_F(LINEAR_UNIT(mbl.z_values[px][py]), 5);
-          SERIAL_EOL();
+          SERIAL_ECHOLNPGM("Mesh Bed Leveling:");
         }
-      }
-
-    #elif ENABLED(AUTO_BED_LEVELING_UBL)
-
-      if (!forReplay) {
         CONFIG_ECHO_START;
-        ubl.echo_name();
-        SERIAL_ECHOLNPGM(":");
-      }
-      CONFIG_ECHO_START;
-      SERIAL_ECHOPAIR("  M420 S", LEVELING_IS_ACTIVE() ? 1 : 0);
-      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        SERIAL_ECHOPAIR(" Z", planner.z_fade_height);
+
+      #elif ENABLED(AUTO_BED_LEVELING_UBL)
+
+        if (!forReplay) {
+          CONFIG_ECHO_START;
+          ubl.echo_name();
+          SERIAL_ECHOLNPGM(":");
+        }
+        CONFIG_ECHO_START;
+
+      #elif HAS_ABL
+
+        if (!forReplay) {
+          CONFIG_ECHO_START;
+          SERIAL_ECHOLNPGM("Auto Bed Leveling:");
+        }
+        CONFIG_ECHO_START;
+
       #endif
-      SERIAL_EOL();
 
-      if (!forReplay) {
-        SERIAL_EOL();
-        ubl.report_state();
-        SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.state.storage_slot);
-        SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes());
-        SERIAL_ECHOLNPGM(" meshes.\n");
-      }
-
-    #elif HAS_ABL
-
-      if (!forReplay) {
-        CONFIG_ECHO_START;
-        SERIAL_ECHOLNPGM("Auto Bed Leveling:");
-      }
       CONFIG_ECHO_START;
-      SERIAL_ECHOPAIR("  M420 S", LEVELING_IS_ACTIVE() ? 1 : 0);
+      SERIAL_ECHOPAIR("  M420 S", planner.leveling_active ? 1 : 0);
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
         SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.z_fade_height));
       #endif
       SERIAL_EOL();
 
-    #endif
+      #if ENABLED(MESH_BED_LEVELING)
+
+        for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
+          for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
+            CONFIG_ECHO_START;
+            SERIAL_ECHOPAIR("  G29 S3 X", (int)px + 1);
+            SERIAL_ECHOPAIR(" Y", (int)py + 1);
+            SERIAL_ECHOPGM(" Z");
+            SERIAL_PROTOCOL_F(LINEAR_UNIT(mbl.z_values[px][py]), 5);
+            SERIAL_EOL();
+          }
+        }
+
+      #elif ENABLED(AUTO_BED_LEVELING_UBL)
+
+        if (!forReplay) {
+          SERIAL_EOL();
+          ubl.report_state();
+          SERIAL_ECHOLNPAIR("\nActive Mesh Slot: ", ubl.state.storage_slot);
+          SERIAL_ECHOPAIR("EEPROM can hold ", calc_num_meshes());
+          SERIAL_ECHOLNPGM(" meshes.\n");
+        }
+
+      #endif
+
+    #endif // HAS_LEVELING
 
     #if ENABLED(DELTA)
       if (!forReplay) {
@@ -1757,7 +1767,7 @@ void MarlinSettings::reset() {
     #endif // FWRETRACT
 
     /**
-     * Auto Bed Leveling
+     * Probe Offset
      */
     #if HAS_BED_PROBE
       if (!forReplay) {
diff --git a/Marlin/mesh_bed_leveling.cpp b/Marlin/mesh_bed_leveling.cpp
index 3da19d97ed4..27344599b42 100644
--- a/Marlin/mesh_bed_leveling.cpp
+++ b/Marlin/mesh_bed_leveling.cpp
@@ -26,7 +26,7 @@
 
   mesh_bed_leveling mbl;
 
-  uint8_t mesh_bed_leveling::status;
+  bool mesh_bed_leveling::has_mesh;
 
   float mesh_bed_leveling::z_offset,
         mesh_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y],
@@ -42,7 +42,7 @@
   }
 
   void mesh_bed_leveling::reset() {
-    status = MBL_STATUS_NONE;
+    has_mesh = false;
     z_offset = 0;
     ZERO(z_values);
   }
diff --git a/Marlin/mesh_bed_leveling.h b/Marlin/mesh_bed_leveling.h
index f7b701bf28e..87afeb55865 100644
--- a/Marlin/mesh_bed_leveling.h
+++ b/Marlin/mesh_bed_leveling.h
@@ -33,18 +33,12 @@
     MeshReset
   };
 
-  enum MBLStatus {
-    MBL_STATUS_NONE = 0,
-    MBL_STATUS_HAS_MESH_BIT = 0,
-    MBL_STATUS_ACTIVE_BIT = 1
-  };
-
   #define MESH_X_DIST ((MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_POINTS_X - 1))
   #define MESH_Y_DIST ((MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_POINTS_Y - 1))
 
   class mesh_bed_leveling {
   public:
-    static uint8_t status; // Has Mesh and Is Active bits
+    static bool has_mesh;
     static float z_offset,
                  z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y],
                  index_to_xpos[GRID_MAX_POINTS_X],
@@ -56,11 +50,6 @@
 
     static void set_z(const int8_t px, const int8_t py, const float &z) { z_values[px][py] = z; }
 
-    static bool active()                       { return TEST(status, MBL_STATUS_ACTIVE_BIT); }
-    static void set_active(const bool onOff)   { onOff ? SBI(status, MBL_STATUS_ACTIVE_BIT) : CBI(status, MBL_STATUS_ACTIVE_BIT); }
-    static bool has_mesh()                     { return TEST(status, MBL_STATUS_HAS_MESH_BIT); }
-    static void set_has_mesh(const bool onOff) { onOff ? SBI(status, MBL_STATUS_HAS_MESH_BIT) : CBI(status, MBL_STATUS_HAS_MESH_BIT); }
-
     static inline void zigzag(const int8_t index, int8_t &px, int8_t &py) {
       px = index % (GRID_MAX_POINTS_X);
       py = index / (GRID_MAX_POINTS_X);
diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp
index 97cdde522a6..0af78e3dd35 100644
--- a/Marlin/planner.cpp
+++ b/Marlin/planner.cpp
@@ -104,17 +104,16 @@ float Planner::min_feedrate_mm_s,
       Planner::max_jerk[XYZE],       // The largest speed change requiring no acceleration
       Planner::min_travel_feedrate_mm_s;
 
-#if HAS_ABL
-  bool Planner::abl_enabled = false; // Flag that auto bed leveling is enabled
-#endif
-
-#if ABL_PLANAR
-  matrix_3x3 Planner::bed_level_matrix; // Transform to compensate for bed level
-#endif
-
-#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-  float Planner::z_fade_height, // Initialized by settings.load()
-        Planner::inverse_z_fade_height;
+#if HAS_LEVELING
+  bool Planner::leveling_active = false; // Flag that auto bed leveling is enabled
+  #if ABL_PLANAR
+    matrix_3x3 Planner::bed_level_matrix; // Transform to compensate for bed level
+  #endif
+  #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+    float Planner::z_fade_height,      // Initialized by settings.load()
+          Planner::inverse_z_fade_height,
+          Planner::last_raw_lz;
+  #endif
 #endif
 
 #if ENABLED(AUTOTEMP)
@@ -528,46 +527,31 @@ void Planner::check_axes_activity() {
    */
   void Planner::apply_leveling(float &lx, float &ly, float &lz) {
 
+    if (!leveling_active) return;
+
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+      const float fade_scaling_factor = fade_scaling_factor_for_z(lz);
+      if (!fade_scaling_factor) return;
+    #else
+      constexpr float fade_scaling_factor = 1.0;
+    #endif
+
     #if ENABLED(AUTO_BED_LEVELING_UBL)
-      if (!ubl.state.active) return;
-      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        // if z_fade_height enabled (nonzero) and raw_z above it, no leveling required
-        if (planner.z_fade_height && planner.z_fade_height <= RAW_Z_POSITION(lz)) return;
-        lz += ubl.get_z_correction(lx, ly) * ubl.fade_scaling_factor_for_z(lz);
-      #else // no fade
-        lz += ubl.get_z_correction(lx, ly);
-      #endif // FADE
-    #endif // UBL
 
-    #if HAS_ABL
-      if (!abl_enabled) return;
-    #endif
+      lz += ubl.get_z_correction(lx, ly) * fade_scaling_factor;
 
-    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) && DISABLED(AUTO_BED_LEVELING_UBL)
-      static float z_fade_factor = 1.0, last_raw_lz = -999.0;
-      if (z_fade_height) {
-        const float raw_lz = RAW_Z_POSITION(lz);
-        if (raw_lz >= z_fade_height) return;
-        if (last_raw_lz != raw_lz) {
-          last_raw_lz = raw_lz;
-          z_fade_factor = 1.0 - raw_lz * inverse_z_fade_height;
-        }
-      }
-      else
-        z_fade_factor = 1.0;
-    #endif
+    #elif ENABLED(MESH_BED_LEVELING)
 
-    #if ENABLED(MESH_BED_LEVELING)
-
-      if (mbl.active())
-        lz += mbl.get_z(RAW_X_POSITION(lx), RAW_Y_POSITION(ly)
-          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-            , z_fade_factor
-          #endif
-          );
+      lz += mbl.get_z(RAW_X_POSITION(lx), RAW_Y_POSITION(ly)
+        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+          , fade_scaling_factor
+        #endif
+      );
 
     #elif ABL_PLANAR
 
+      UNUSED(fade_scaling_factor);
+
       float dx = RAW_X_POSITION(lx) - (X_TILT_FULCRUM),
             dy = RAW_Y_POSITION(ly) - (Y_TILT_FULCRUM),
             dz = RAW_Z_POSITION(lz);
@@ -581,63 +565,56 @@ void Planner::check_axes_activity() {
     #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
 
       float tmp[XYZ] = { lx, ly, 0 };
-      lz += bilinear_z_offset(tmp)
-        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-          * z_fade_factor
-        #endif
-      ;
+      lz += bilinear_z_offset(tmp) * fade_scaling_factor;
 
     #endif
   }
 
   void Planner::unapply_leveling(float logical[XYZ]) {
 
+    #if HAS_LEVELING
+      if (!leveling_active) return;
+    #endif
+
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+      if (!leveling_active_at_z(logical[Z_AXIS])) return;
+    #endif
+
     #if ENABLED(AUTO_BED_LEVELING_UBL)
 
-      if (ubl.state.active) {
+      const float z_physical = RAW_Z_POSITION(logical[Z_AXIS]),
+                  z_correct = ubl.get_z_correction(logical[X_AXIS], logical[Y_AXIS]),
+                  z_virtual = z_physical - z_correct;
+            float z_logical = LOGICAL_Z_POSITION(z_virtual);
 
-        const float z_physical = RAW_Z_POSITION(logical[Z_AXIS]),
-                    z_correct = ubl.get_z_correction(logical[X_AXIS], logical[Y_AXIS]),
-                    z_virtual = z_physical - z_correct;
-              float z_logical = LOGICAL_Z_POSITION(z_virtual);
+      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
 
-        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+        // for P=physical_z, L=logical_z, M=mesh_z, H=fade_height,
+        // Given P=L+M(1-L/H) (faded mesh correction formula for L<H)
+        //  then L=P-M(1-L/H)
+        //    so L=P-M+ML/H
+        //    so L-ML/H=P-M
+        //    so L(1-M/H)=P-M
+        //    so L=(P-M)/(1-M/H) for L<H
 
-          // for P=physical_z, L=logical_z, M=mesh_z, H=fade_height,
-          // Given P=L+M(1-L/H) (faded mesh correction formula for L<H)
-          //  then L=P-M(1-L/H)
-          //    so L=P-M+ML/H
-          //    so L-ML/H=P-M
-          //    so L(1-M/H)=P-M
-          //    so L=(P-M)/(1-M/H) for L<H
+        if (planner.z_fade_height) {
+          if (z_logical >= planner.z_fade_height)
+            z_logical = LOGICAL_Z_POSITION(z_physical);
+          else
+            z_logical /= 1.0 - z_correct * planner.inverse_z_fade_height;
+        }
 
-          if (planner.z_fade_height) {
-            if (z_logical >= planner.z_fade_height)
-              z_logical = LOGICAL_Z_POSITION(z_physical);
-            else
-              z_logical /= 1.0 - z_correct * planner.inverse_z_fade_height;
-          }
+      #endif // ENABLE_LEVELING_FADE_HEIGHT
 
-        #endif // ENABLE_LEVELING_FADE_HEIGHT
-
-        logical[Z_AXIS] = z_logical;
-      }
+      logical[Z_AXIS] = z_logical;
 
       return; // don't fall thru to other ENABLE_LEVELING_FADE_HEIGHT logic
 
     #endif
 
-    #if HAS_ABL
-      if (!abl_enabled) return;
-    #endif
-
-    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      if (z_fade_height && RAW_Z_POSITION(logical[Z_AXIS]) >= z_fade_height) return;
-    #endif
-
     #if ENABLED(MESH_BED_LEVELING)
 
-      if (mbl.active()) {
+      if (leveling_active) {
         #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
           const float c = mbl.get_z(RAW_X_POSITION(logical[X_AXIS]), RAW_Y_POSITION(logical[Y_AXIS]), 1.0);
           logical[Z_AXIS] = (z_fade_height * (RAW_Z_POSITION(logical[Z_AXIS]) - c)) / (z_fade_height - c);
diff --git a/Marlin/planner.h b/Marlin/planner.h
index 8b1de85ad6d..3351697eac9 100644
--- a/Marlin/planner.h
+++ b/Marlin/planner.h
@@ -154,15 +154,14 @@ class Planner {
                  max_jerk[XYZE],       // The largest speed change requiring no acceleration
                  min_travel_feedrate_mm_s;
 
-    #if HAS_ABL
-      static bool abl_enabled;              // Flag that bed leveling is enabled
+    #if HAS_LEVELING
+      static bool leveling_active;          // Flag that bed leveling is enabled
       #if ABL_PLANAR
         static matrix_3x3 bed_level_matrix; // Transform to compensate for bed level
       #endif
-    #endif
-
-    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      static float z_fade_height, inverse_z_fade_height;
+      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+        static float z_fade_height, inverse_z_fade_height;
+      #endif
     #endif
 
     #if ENABLED(LIN_ADVANCE)
@@ -192,6 +191,10 @@ class Planner {
      */
     static uint32_t cutoff_long;
 
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+      static float last_raw_lz;
+    #endif
+
     #if ENABLED(DISABLE_INACTIVE_EXTRUDER)
       /**
        * Counters to manage disabling inactive extruders
@@ -243,6 +246,52 @@ class Planner {
 
     static bool is_full() { return (block_buffer_tail == BLOCK_MOD(block_buffer_head + 1)); }
 
+    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
+
+      /**
+       * Get the Z leveling fade factor based on the given Z height,
+       * re-calculating only when needed.
+       *
+       *  Returns 1.0 if planner.z_fade_height is 0.0.
+       *  Returns 0.0 if Z is past the specified 'Fade Height'.
+       */
+      inline static float fade_scaling_factor_for_z(const float &lz) {
+        static float z_fade_factor = 1.0;
+        if (z_fade_height) {
+          const float raw_lz = RAW_Z_POSITION(lz);
+          if (raw_lz >= z_fade_height) return 0.0;
+          if (last_raw_lz != raw_lz) {
+            last_raw_lz = raw_lz;
+            z_fade_factor = 1.0 - raw_lz * inverse_z_fade_height;
+          }
+          return z_fade_factor;
+        }
+        return 1.0;
+      }
+
+      FORCE_INLINE static void force_fade_recalc() { last_raw_lz = -999.999; }
+
+      FORCE_INLINE static void set_z_fade_height(const float &zfh) {
+        z_fade_height = zfh > 0 ? zfh : 0;
+        inverse_z_fade_height = RECIPROCAL(z_fade_height);
+        force_fade_recalc();
+      }
+
+      FORCE_INLINE static bool leveling_active_at_z(const float &lz) {
+        return !z_fade_height || RAW_Z_POSITION(lz) < z_fade_height;
+      }
+
+    #else
+
+      FORCE_INLINE static float fade_scaling_factor_for_z(const float &lz) {
+        UNUSED(lz);
+        return 1.0;
+      }
+
+      FORCE_INLINE static bool leveling_active_at_z(const float &lz) { return true; }
+
+    #endif
+
     #if PLANNER_LEVELING
 
       #define ARG_X float lx
@@ -468,16 +517,6 @@ class Planner {
 
 #define PLANNER_XY_FEEDRATE() (min(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS]))
 
-#if ENABLED(MESH_BED_LEVELING)
-  #define LEVELING_IS_ACTIVE() (mesh_bed_leveling::active())
-#elif ENABLED(AUTO_BED_LEVELING_UBL)
-  #define LEVELING_IS_ACTIVE() (unified_bed_leveling::state.active)
-#elif HAS_ABL
-  #define LEVELING_IS_ACTIVE() (Planner::abl_enabled)
-#else
-  #define LEVELING_IS_ACTIVE() (false)
-#endif
-
 extern Planner planner;
 
 #endif // PLANNER_H
diff --git a/Marlin/ubl.cpp b/Marlin/ubl.cpp
index f0b4666778a..e9bbe483b15 100644
--- a/Marlin/ubl.cpp
+++ b/Marlin/ubl.cpp
@@ -28,8 +28,7 @@
   #include "ubl.h"
   #include "hex_print_routines.h"
   #include "temperature.h"
-
-  extern Planner planner;
+  #include "planner.h"
 
   /**
    * These support functions allow the use of large bit arrays of flags that take very
@@ -48,7 +47,7 @@
   void unified_bed_leveling::report_state() {
     echo_name();
     SERIAL_PROTOCOLPGM(" System v" UBL_VERSION " ");
-    if (!state.active) SERIAL_PROTOCOLPGM("in");
+    if (!planner.leveling_active) SERIAL_PROTOCOLPGM("in");
     SERIAL_PROTOCOLLNPGM("active.");
     safe_delay(50);
   }
@@ -64,8 +63,7 @@
 
   ubl_state unified_bed_leveling::state;
 
-  float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y],
-        unified_bed_leveling::last_specified_z;
+  float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
 
   // 15 is the maximum nubmer of grid points supported + 1 safety margin for now,
   // until determinism prevails
@@ -86,10 +84,9 @@
     set_bed_leveling_enabled(false);
     state.storage_slot = -1;
     #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-      planner.z_fade_height = 10.0;
+      planner.set_z_fade_height(10.0);
     #endif
     ZERO(z_values);
-    last_specified_z = -999.9;
   }
 
   void unified_bed_leveling::invalidate() {
diff --git a/Marlin/ubl.h b/Marlin/ubl.h
index c80291a18ed..deec65ef609 100644
--- a/Marlin/ubl.h
+++ b/Marlin/ubl.h
@@ -84,8 +84,6 @@
   class unified_bed_leveling {
     private:
 
-      static float last_specified_z;
-
       static int    g29_verbose_level,
                     g29_phase_value,
                     g29_repetition_cnt,
@@ -361,31 +359,6 @@
         return z0;
       }
 
-      /**
-       * This function sets the Z leveling fade factor based on the given Z height,
-       * only re-calculating when necessary.
-       *
-       *  Returns 1.0 if planner.z_fade_height is 0.0.
-       *  Returns 0.0 if Z is past the specified 'Fade Height'.
-       */
-      #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        static inline float fade_scaling_factor_for_z(const float &lz) {
-          if (planner.z_fade_height == 0.0) return 1.0;
-          static float fade_scaling_factor = 1.0;
-          const float rz = RAW_Z_POSITION(lz);
-          if (last_specified_z != rz) {
-            last_specified_z = rz;
-            fade_scaling_factor =
-              rz < planner.z_fade_height
-                ? 1.0 - (rz * planner.inverse_z_fade_height)
-                : 0.0;
-          }
-          return fade_scaling_factor;
-        }
-      #else
-        FORCE_INLINE static float fade_scaling_factor_for_z(const float &lz) { return 1.0; }
-      #endif
-
       FORCE_INLINE static float mesh_index_to_xpos(const uint8_t i) {
         return i < GRID_MAX_POINTS_X ? pgm_read_float(&_mesh_index_to_xpos[i]) : UBL_MESH_MIN_X + i * (MESH_X_DIST);
       }
diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp
index 73dc3c06f00..ab0db8b0600 100644
--- a/Marlin/ubl_G29.cpp
+++ b/Marlin/ubl_G29.cpp
@@ -1165,7 +1165,7 @@
 
       return;
     }
-    ubl_state_at_invocation = state.active;
+    ubl_state_at_invocation = planner.leveling_active;
     set_bed_leveling_enabled(false);
   }
 
diff --git a/Marlin/ubl_motion.cpp b/Marlin/ubl_motion.cpp
index 28fd39daeb4..a7a76132b60 100644
--- a/Marlin/ubl_motion.cpp
+++ b/Marlin/ubl_motion.cpp
@@ -186,7 +186,7 @@
       // are going to apply the Y-Distance into the cell to interpolate the final Z correction.
 
       const float yratio = (RAW_Y_POSITION(end[Y_AXIS]) - mesh_index_to_ypos(cell_dest_yi)) * (1.0 / (MESH_Y_DIST));
-      float z0 = cell_dest_yi < GRID_MAX_POINTS_Y - 1 ? (z1 + (z2 - z1) * yratio) * fade_scaling_factor_for_z(end[Z_AXIS]) : 0.0;
+      float z0 = cell_dest_yi < GRID_MAX_POINTS_Y - 1 ? (z1 + (z2 - z1) * yratio) * planner.fade_scaling_factor_for_z(end[Z_AXIS]) : 0.0;
 
       /**
        * If part of the Mesh is undefined, it will show up as NAN
@@ -270,9 +270,8 @@
          */
         const float x = inf_m_flag ? start[X_AXIS] : (next_mesh_line_y - c) / m;
 
-        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi, current_yi);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi, current_yi)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -335,9 +334,8 @@
         const float next_mesh_line_x = LOGICAL_X_POSITION(mesh_index_to_xpos(current_xi)),
                     y = m * next_mesh_line_x + c;   // Calculate Y at the next X mesh line
 
-        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi, current_yi);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi, current_yi)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -408,9 +406,8 @@
 
       if (left_flag == (x > next_mesh_line_x)) { // Check if we hit the Y line first
         // Yes!  Crossing a Y Mesh Line next
-        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi - left_flag, current_yi + dyi);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_x_on_horizontal_mesh_line(x, current_xi - left_flag, current_yi + dyi)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -436,9 +433,8 @@
       }
       else {
         // Yes!  Crossing a X Mesh Line next
-        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi + dxi, current_yi - down_flag);
-
-        z0 *= fade_scaling_factor_for_z(end[Z_AXIS]);
+        float z0 = z_correction_for_y_on_vertical_mesh_line(y, current_xi + dxi, current_yi - down_flag)
+                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
 
         /**
          * If part of the Mesh is undefined, it will show up as NAN
@@ -603,7 +599,7 @@
 
       // Only compute leveling per segment if ubl active and target below z_fade_height.
 
-      if (!state.active || above_fade_height) {   // no mesh leveling
+      if (!planner.leveling_active || !planner.leveling_active_at_z(ltarget[Z_AXIS])) {   // no mesh leveling
 
         do {
 
@@ -629,7 +625,9 @@
       // Otherwise perform per-segment leveling
 
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        const float fade_scaling_factor = fade_scaling_factor_for_z(ltarget[Z_AXIS]);
+        const float fade_scaling_factor = planner.fade_scaling_factor_for_z(ltarget[Z_AXIS]);
+      #else
+        constexpr float fade_scaling_factor = 1.0;
       #endif
 
       // increment to first segment destination
@@ -661,7 +659,7 @@
               z_x0y1 = z_values[cell_xi  ][cell_yi+1],  // z at lower right corner
               z_x1y1 = z_values[cell_xi+1][cell_yi+1];  // z at upper right corner
 
-        if (isnan(z_x0y0)) z_x0y0 = 0;              // ideally activating state.active (G29 A)
+        if (isnan(z_x0y0)) z_x0y0 = 0;              // ideally activating planner.leveling_active (G29 A)
         if (isnan(z_x1y0)) z_x1y0 = 0;              //   should refuse if any invalid mesh points
         if (isnan(z_x0y1)) z_x0y1 = 0;              //   in order to avoid isnan tests per cell,
         if (isnan(z_x1y1)) z_x1y1 = 0;              //   thus guessing zero for undefined points
@@ -690,11 +688,7 @@
 
         for(;;) {  // for all segments within this mesh cell
 
-          float z_cxcy = z_cxy0 + z_cxym * cy;      // interpolated mesh z height along cx at cy
-
-          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-            z_cxcy *= fade_scaling_factor;          // apply fade factor to interpolated mesh height
-          #endif
+          float z_cxcy = (z_cxy0 + z_cxym * cy) * fade_scaling_factor; // interpolated mesh z height along cx at cy, scaled for fade
 
           if (--segments == 0) {                    // if this is last segment, use ltarget for exact
             seg_rx = RAW_X_POSITION(ltarget[X_AXIS]);
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index a9fa5fa985e..98c339ddc87 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -1089,7 +1089,7 @@ void kill_screen(const char* lcd_msg) {
           const float new_zoffset = zprobe_zoffset + planner.steps_to_mm[Z_AXIS] * babystep_increment;
           if (WITHIN(new_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) {
 
-            if (planner.abl_enabled)
+            if (planner.leveling_active)
               thermalManager.babystep_axis(Z_AXIS, babystep_increment);
 
             zprobe_zoffset = new_zoffset;
@@ -1791,7 +1791,7 @@ void kill_screen(const char* lcd_msg) {
 
             _lcd_after_probing();
 
-            mbl.set_has_mesh(true);
+            mbl.has_mesh = true;
             mesh_probing_done();
 
           #endif
@@ -1937,12 +1937,11 @@ void kill_screen(const char* lcd_msg) {
       if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]))
         MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
       else if (leveling_is_valid()) {
-        _level_state = LEVELING_IS_ACTIVE();
+        _level_state = planner.leveling_active;
         MENU_ITEM_EDIT_CALLBACK(bool, MSG_BED_LEVELING, &_level_state, _lcd_toggle_bed_leveling);
       }
 
       #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
-        set_z_fade_height(planner.z_fade_height);
         MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float62, MSG_Z_FADE_HEIGHT, &planner.z_fade_height, 0.0, 100.0, _lcd_set_z_fade_height);
       #endif
 
diff --git a/Marlin/ultralcd_impl_HD44780.h b/Marlin/ultralcd_impl_HD44780.h
index adb7eef505a..e25d4f61bc7 100644
--- a/Marlin/ultralcd_impl_HD44780.h
+++ b/Marlin/ultralcd_impl_HD44780.h
@@ -792,7 +792,7 @@ static void lcd_implementation_status_screen() {
     lcd.print(ftostr52sp(FIXFLOAT(current_position[Z_AXIS])));
 
     #if HAS_LEVELING
-      lcd.write(LEVELING_IS_ACTIVE() || blink ? '_' : ' ');
+      lcd.write(planner.leveling_active || blink ? '_' : ' ');
     #endif
 
   #endif // LCD_HEIGHT > 2