static void toCircle()

in native-filters/src/main/jni/filters/rounding_filter.c [160:264]


static void toCircle(
    JNIEnv* env,
    pixel_t* pixelPtr,
    const int w,
    const int h) {
  const int centerX = w / 2;
  const int centerY = h / 2;
  const int radius = min(w,h) / 2;

  if (radius < 1) {
    safe_throw_exception(env, "Circle radius too small!");
    return;
  }
  if (w <= 0 || h <= 0 || w > BITMAP_MAX_DIMENSION || h > BITMAP_MAX_DIMENSION) {
    safe_throw_exception(env, "Invalid bitmap dimensions!");
    return;
  }
  if (centerX < 0 || centerY < 0 || centerX >= w || centerY >= h) {
    safe_throw_exception(env, "Invalid circle center coordinates!");
    return;
  }

  int x = radius - 1;
  int y = 0;

  const int maxX = centerX + x;
  const int maxY = centerY + x;
  const int minX = centerX - x;
  const int minY = centerY - x;

  if (minX < 0 || minY < 0 || maxX >= w || maxY >= h) {
    safe_throw_exception(env, "Circle must be fully visible!");
    return;
  }

  int dx = 1;
  int dy = 1;

  const int rInc = - radius * 2;
  int err = dx + rInc;

  while (x >= y) {

    const int cXpX = centerX + x;
    const int cXmX = centerX - x;
    const int cXpY = centerX + y;
    const int cXmY = centerX - y;

    const int cYpX = centerY + x;
    const int cYmX = centerY - x;
    const int cYpY = centerY + y;
    const int cYmY = centerY - y;

    if (x < 0 || cXpY >= w || cXmY < 0 || cYpY >= h || cYmY < 0) {
      safe_throw_exception(env, "Invalid internal state!");
      return;
    }

    const int offA = w * cYpY;
    const int offB = w * cYmY;
    const int offC = w * cYpX;
    const int offD = w * cYmX;

    const size_t leftBytesX = sizeof(pixel_t) * cXmX;
    const size_t leftBytesY = sizeof(pixel_t) * cXmY;
    const size_t rightBytesX = sizeof(pixel_t) * (w-cXpX);
    const size_t rightBytesY = sizeof(pixel_t) * (w-cXpY);

    // clear left
    memset(pixelPtr + offA, TRANSPARENT_PIXEL_COLOR, leftBytesX);
    memset(pixelPtr + offB, TRANSPARENT_PIXEL_COLOR, leftBytesX);
    memset(pixelPtr + offC, TRANSPARENT_PIXEL_COLOR, leftBytesY);
    memset(pixelPtr + offD, TRANSPARENT_PIXEL_COLOR, leftBytesY);

    // clear right
    memset(pixelPtr + offA + cXpX, TRANSPARENT_PIXEL_COLOR, rightBytesX);
    memset(pixelPtr + offB + cXpX, TRANSPARENT_PIXEL_COLOR, rightBytesX);
    memset(pixelPtr + offC + cXpY, TRANSPARENT_PIXEL_COLOR, rightBytesY);
    memset(pixelPtr + offD + cXpY, TRANSPARENT_PIXEL_COLOR, rightBytesY);

    if (err <= 0) {
      y++;

      dy += 2;
      err += dy;
    }
    if (err > 0) {
      x--;

      dx += 2;
      err += dx + rInc;
    }
  }

  const size_t lineBytes = sizeof(pixel_t) * w;

  // clear top / bottom if height > width
  for (int i = centerY - radius; i >= 0; i--) {
    memset(pixelPtr + i * w, TRANSPARENT_PIXEL_COLOR, lineBytes);
  }

  for (int i = centerY + radius; i < h; i++) {
    memset(pixelPtr + i * w, TRANSPARENT_PIXEL_COLOR, lineBytes);
  }
}