std::unique_ptr BicubicScalingBlockImpl::produce()

in cpp/spectrum/core/proc/ScalingScanlineProcessingBlock.cpp [226:330]


std::unique_ptr<image::Scanline> BicubicScalingBlockImpl::produce() {
  if (outputScanline == outputSize.height) {
    return nullptr;
  }

  auto result =
      std::make_unique<image::Scanline>(_pixelSpecification, outputSize.width);

  const float middleY = 0.5f * invScalingY *
      static_cast<float>(outputScanline + outputScanline + 1);

  // shift from pixel center to logical index
  const float logicalMiddleY = clamp(middleY - 0.5f, 0.0f, inputSize.height);

  const int y1 = static_cast<int>(floor(logicalMiddleY));
  const int y2 = y1 < inputSize.height - 1 ? y1 + 1 : y1;
  SPECTRUM_ENFORCE_IF_NOT(y1 >= 0 && y1 <= y2 && y2 < inputSize.height);

  const float deltaY = (y1 == y2) ? 0 : (logicalMiddleY - y1) / (y2 - y1);
  SPECTRUM_ENFORCE_IF_NOT(deltaY >= 0.0f && deltaY <= 1.0f);

  const int y0 = y1 == 0 ? 0 : y1 - 1;
  const int y3 = y2 < inputSize.height - 1 ? y2 + 1 : y2;
  SPECTRUM_ENFORCE_IF_NOT(y0 >= 0 && y0 <= y3 && y3 < inputSize.height);

  if (static_cast<size_t>(y3) >= input.size()) {
    return nullptr;
  }

  for (int xOffset = 0; xOffset < outputSize.width; xOffset++) {
    const float middleX =
        0.5f * invScalingX * static_cast<float>(xOffset + xOffset + 1);

    // shift from pixel center to logical index
    const float logicalMiddleX = clamp(middleX - 0.5f, 0.0f, inputSize.width);

    const int x1 = static_cast<int>(floor(logicalMiddleX));
    const int x2 = x1 < inputSize.width - 1 ? x1 + 1 : x1;
    SPECTRUM_ENFORCE_IF_NOT(x1 >= 0 && x1 <= x2 && x2 < inputSize.width);

    const float deltaX = (x1 == x2) ? 0 : (logicalMiddleX - x1) / (x2 - x1);
    SPECTRUM_ENFORCE_IF_NOT(deltaX >= 0.0f && deltaX <= 1.0f);

    const int x0 = x1 == 0 ? 0 : x1 - 1;
    const int x3 = x2 < inputSize.width - 1 ? x2 + 1 : x2;
    SPECTRUM_ENFORCE_IF_NOT(x0 >= 0 && x0 <= x3 && x3 < inputSize.width);

    const auto numberOfComponents = _pixelSpecification.numberOfComponents();
    const auto bicubicSum0 = bicubicComputeAndClamp(
        numberOfComponents,
        deltaX,
        (*input[y0]).dataAtPixel(x0),
        (*input[y0]).dataAtPixel(x1),
        (*input[y0]).dataAtPixel(x2),
        (*input[y0]).dataAtPixel(x3));

    const auto bicubicSum1 = bicubicComputeAndClamp(
        numberOfComponents,
        deltaX,
        (*input[y1]).dataAtPixel(x0),
        (*input[y1]).dataAtPixel(x1),
        (*input[y1]).dataAtPixel(x2),
        (*input[y1]).dataAtPixel(x3));

    const auto bicubicSum2 = bicubicComputeAndClamp(
        numberOfComponents,
        deltaX,
        (*input[y2]).dataAtPixel(x0),
        (*input[y2]).dataAtPixel(x1),
        (*input[y2]).dataAtPixel(x2),
        (*input[y2]).dataAtPixel(x3));

    const auto bicubicSum3 = bicubicComputeAndClamp(
        numberOfComponents,
        deltaX,
        (*input[y3]).dataAtPixel(x0),
        (*input[y3]).dataAtPixel(x1),
        (*input[y3]).dataAtPixel(x2),
        (*input[y3]).dataAtPixel(x3));

    const auto pxl = bicubicComputeAndClamp(
        numberOfComponents,
        deltaY,
        bicubicSum0.data(),
        bicubicSum1.data(),
        bicubicSum2.data(),
        bicubicSum3.data());

    auto dst = result->dataAtPixel(xOffset);
    for (std::uint8_t componentOffset = 0; componentOffset < numberOfComponents;
         componentOffset++) {
      *(dst + componentOffset) = pxl[componentOffset];
    }
  }

  // free scanlines that will not be touched again
  for (int i = nextLineToRelease; i < y0; i++) {
    SPECTRUM_ENFORCE_IF(input[i] == nullptr);
    input[i].reset();
  }
  nextLineToRelease = y0;

  ++outputScanline;
  return result;
}