Fading Rectangle Color on Hover in SDL2

What if I want the rectangle's color to change gradually when hovered (fade)?

Creating a gradual fade effect instead of an instant color change requires managing the transition over time. The current code jumps directly between Color and HoverColor based on the isPointerHovering state. Fading involves calculating intermediate colors between these two states.

Core Concept: Interpolation

The key technique is linear interpolation (often shortened to "lerp"). Lerping allows you to find a value partway between a starting value and an ending value, based on a progress factor (usually a float t ranging from 0.0 to 1.0).

The formula for lerp is: interpolatedValue = startValue + (endValue - startValue) * t

  • If t is 0.0, the result is startValue.
  • If t is 1.0, the result is endValue.
  • If t is 0.5, the result is halfway between startValue and endValue.

We need to apply this formula to each color channel (Red, Green, Blue) independently.

Implementing the Fade

Add State for Fade Progress: The Rectangle class needs a member variable to track the current progress of the fade, typically a float. Let's call it hoverFadeProgress, ranging from 0.0 (fully normal color) to 1.0 (fully hover color).

// Rectangle.h
// ...
private:
  // ... existing members ...
  SDL_Color Color{255, 0, 0};
  SDL_Color HoverColor{0, 0, 255};
  bool isPointerHovering{false};
  float hoverFadeProgress{0.0f}; // Add this

Add an Update() Method: The fade needs to progress over time. This typically happens in an Update() method that gets called each frame, often receiving the time elapsed since the last frame (deltaTime) for smooth, frame-rate-independent animation.

// Rectangle.h
// ...
public:
  // ... existing methods ...
  void Update(float deltaTime) {
    const float fadeSpeed{4.0f}; // Adjust speed as needed

    if (isPointerHovering) {
      // Fade towards hover color (increase progress)
      hoverFadeProgress += fadeSpeed * deltaTime;
      if (hoverFadeProgress > 1.0f) {
         hoverFadeProgress = 1.0f;
      }
    } else {
      // Fade towards normal color (decrease progress)
      hoverFadeProgress -= fadeSpeed * deltaTime;
      if (hoverFadeProgress < 0.0f) {
        hoverFadeProgress = 0.0f;
      }
    }
  }
// ...

You would need to call Rect.Update(deltaTime) in your main loop, which requires calculating deltaTime (a more advanced topic involving timing).

We cover Update() methods (sometimes also called Tick() methods) and timing in detail later in the course.

Modify Render() to Interpolate: Instead of instantly choosing Color or HoverColor, the Render() function now calculates the intermediate color based on hoverFadeProgress.

// Rectangle.h
// ...

// Helper function for lerping unsigned chars (like color channels)
Uint8 LerpColorChannel(Uint8 start, Uint8 end, float t) {
  // Perform calculation in float, then cast back
  return static_cast<Uint8>(
    static_cast<float>(start) +
    (static_cast<float>(end) - static_cast<float>(start)) * t
  );
}

void Render(SDL_Surface* Surface) const {
  // Interpolate each channel based on progress
  Uint8 r = LerpColorChannel(
    Color.r, HoverColor.r, hoverFadeProgress);
  Uint8 g = LerpColorChannel(
    Color.g, HoverColor.g, hoverFadeProgress);
  Uint8 b = LerpColorChannel(
    Color.b, HoverColor.b, hoverFadeProgress);

  // Use the interpolated color
  SDL_FillRect(
    Surface, &Rect,
    SDL_MapRGB(Surface->format, r, g, b)
  );
}
// ...

Considerations

  • Timing (deltaTime): Implementing a smooth, frame-rate-independent fade requires calculating the time elapsed between frames (deltaTime). This involves using SDL timing functions like SDL_GetTicks() or SDL_GetPerformanceCounter().
  • Complexity: As you can see, adding smooth fading significantly increases the complexity compared to an instant switch. It requires managing state (hoverFadeProgress) and adding time-based update logic.
  • Easing Functions: For more visually appealing transitions than simple linear interpolation, you can explore "easing functions" which modify the hoverFadeProgress value non-linearly (e.g., ease-in, ease-out).

While this provides the structure, a fully working implementation requires integrating the Update() call and deltaTime calculation into your main loop.

Rectangles and SDL_Rect

Learn to create, render, and interact with basic rectangles using the SDL_Rect and SDL_Color types.

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Difference Between SDL_Rect and SDL_FRect in SDL2
What's the difference between SDL_Rect and SDL_FRect? When should I use floats?
Drawing Rectangle Outlines in SDL2
How do I draw just the outline of a rectangle instead of filling it?
Using Alpha for Semi-Transparency with SDL_Color in SDL2
Can I make the rectangle semi-transparent using the alpha channel in SDL_Color? How?
Passing SDL_Event by Reference (&E) in SDL2 Event Handling
Why pass the SDL_Event by reference (&E) to HandleEvent()?
Alternatives to Structured Binding for SDL_Color in Render()
Why did we use structured binding for the color in Render()? What are the alternatives?
Moving a Rectangle in SDL2
How would I move the rectangle around the screen?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant