SceneObstacle (Vect bl, Vect tr)
   : _left(bl.x()), _bottom(bl.y()), _top(tr.y()), _right(tr.x()) {}
bool SceneObstacle::performCollide (
  Vect pos, Vect::Component rad, Vect spd, float delta,
  Vect& outPos, Vect& outSpd, float& outDelta, Vect& norm
) {
  auto dest = pos + spd * delta;

  auto left = _left + rad;
  auto right = _right - rad;
  auto bottom = _bottom + rad;
  auto top = _top - rad;

  bool outLeft = dest.x() < left;
  bool outRight = dest.x() > right;
  bool outBottom = dest.y() < bottom;
  bool outTop = dest.y() > top;

  if (!(outLeft | outRight | outTop | outBottom)) {
    return false;
  }

  float dltLeft = delta * (pos.x() - left) / (pos.x() - dest.x());
  float dltRight = delta * (pos.x() - right) / (pos.x() - dest.x());
  float dltBottom = delta * (pos.y() - bottom) / (pos.y() - dest.y());
  float dltTop = delta * (pos.y() - top) / (pos.y() - dest.y());

  bool hor = outLeft | outRight;
  bool ver = outTop | outBottom;

  if (hor & ver) {
    // Decide which bounces earlier
    float dltHor = std::min(dltLeft, dltRight);
    float dltVer = std::min(dltTop, dltBottom);

    if (dltHor < dltVer) {
      outTop = outBottom = false;
    } else {
      outLeft = outRight = false;
    }
  }

  if (outLeft) {
    outDelta = delta - dltLeft;
    outPos = pos + spd * dltLeft;
    outSpd = Vect(-spd.x(), spd.y(), 0.f);
    return true;

  } else if (outRight) {
    outDelta = delta - dltRight;
    outPos = pos + spd * dltRight;
    outSpd = Vect(-spd.x(), spd.y(), 0.f);
    return true;

  } else if (outTop) {
    outDelta = delta - dltTop;
    outPos = pos + spd * dltTop;
    outSpd = Vect(spd.x(), -spd.y(), 0.f);
    return true;

  } else/* if (outBottom) */{
    outDelta = delta - dltBottom;
    outPos = pos + spd * dltBottom;
    outSpd = Vect(spd.x(), -spd.y(), 0.f);
    return true;
  }
}