/** Set blur radius in screen pixels. Value is mapped in range [1, 254]. */
  public void setBlurRadius(int radius) {
    // Map radius into scaled down off-screen bitmap size
    radius = Math.round(radius * BITMAP_SCALE_FACTOR);

    // Setup radius struct
    mRadiusStruct.radius = Math.max(1, Math.min(254, radius));
    mRadiusStruct.div = mRadiusStruct.radius + mRadiusStruct.radius + 1;
    mRadiusStruct.divsum = (mRadiusStruct.div + 1) >> 1;
    mRadiusStruct.divsum *= mRadiusStruct.divsum;

    // Prepare dv allocation
    mAllocationDv = Allocation.createSized(mRS, Element.U8(mRS), 256 * mRadiusStruct.divsum);
    mScriptStackBlur.set_initializeDv_divsum(mRadiusStruct.divsum);
    mScriptStackBlur.forEach_initializeDv(mAllocationDv);
  }
  /** Applies blur to current off-screen bitmap */
  public void applyBlur() {
    // Copy current bitmap into allocation
    mAllocationBitmap.copyFrom(mBitmap);

    // Set script variables
    mScriptStackBlur.bind_dv(mAllocationDv);
    mScriptStackBlur.set_bitmap(mAllocationBitmap);
    mScriptStackBlur.set_bitmapTmp(mAllocationBitmapTmp);
    mScriptStackBlur.set_sizeStruct(mSizeStruct);
    mScriptStackBlur.set_radiusStruct(mRadiusStruct);

    // On first step iterate over y = [0, mBitmap.getHeight]
    mLaunchOptions.setX(0, 1);
    mLaunchOptions.setY(0, mBitmap.getHeight());
    mScriptStackBlur.forEach_blurHorizontal(mAllocationBitmap, mLaunchOptions);

    // On second step iterate over x = [0, mBitmap.getWidth]
    mLaunchOptions.setX(0, mBitmap.getWidth());
    mLaunchOptions.setY(0, 1);
    mScriptStackBlur.forEach_blurVertical(mAllocationBitmap, mLaunchOptions);

    // Copy bitmap allocation back to off-screen bitmap
    mAllocationBitmap.copyTo(mBitmap);
  }