@Override
  public int stepSimulation(float timeStep, int maxSubSteps, float fixedTimeStep) {
    int numSimulationSubSteps = 0;

    if (maxSubSteps != 0) {
      // fixed timestep with interpolation
      localTime += timeStep;
      if (localTime >= fixedTimeStep) {
        numSimulationSubSteps = (int) (localTime / fixedTimeStep);
        localTime -= numSimulationSubSteps * fixedTimeStep;
      }
    } else {
      // variable timestep
      fixedTimeStep = timeStep;
      localTime = timeStep;
      if (ScalarUtil.fuzzyZero(timeStep)) {
        numSimulationSubSteps = 0;
        maxSubSteps = 0;
      } else {
        numSimulationSubSteps = 1;
        maxSubSteps = 1;
      }
    }

    // process some debugging flags
    if (getDebugDrawer() != null) {
      BulletGlobals.setDeactivationDisabled(
          (getDebugDrawer().getDebugMode() & DebugDrawModes.NO_DEACTIVATION) != 0);
    }
    if (numSimulationSubSteps != 0) {
      saveKinematicState(fixedTimeStep);

      applyGravity();

      // clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
      int clampedSimulationSteps =
          (numSimulationSubSteps > maxSubSteps) ? maxSubSteps : numSimulationSubSteps;

      for (int i = 0; i < clampedSimulationSteps; i++) {
        internalSingleStepSimulation(fixedTimeStep);
        synchronizeMotionStates();
      }
    }

    synchronizeMotionStates();

    clearForces();

    return numSimulationSubSteps;
  }