bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti colorInput;
	NodeOperation *operation = NULL;

	/* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */
	/* image */
	operation = getInputOperation(0);
	colorInput.xmax = operation->getWidth();
	colorInput.xmin = 0;
	colorInput.ymax = operation->getHeight();
	colorInput.ymin = 0;
	if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) {
		return true;
	}

	/* vector */
	if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
		return true;
	}

	/* scale x */
	operation = getInputOperation(2);
	if (operation->determineDependingAreaOfInterest(input, readOperation, output) ) {
		return true;
	}

	/* scale y */
	operation = getInputOperation(3);
	if (operation->determineDependingAreaOfInterest(input, readOperation, output) ) {
		return true;
	}

	return false;
}
bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input,
                                                          ReadBufferOperation *readOperation,
                                                          rcti *output)
{
  rcti newInput;
  rcti bokehInput;
  const float max_dim = max(this->getWidth(), this->getHeight());

  if (this->m_sizeavailable) {
    newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f);
    newInput.xmin = input->xmin - (this->m_size * max_dim / 100.0f);
    newInput.ymax = input->ymax + (this->m_size * max_dim / 100.0f);
    newInput.ymin = input->ymin - (this->m_size * max_dim / 100.0f);
  }
  else {
    newInput.xmax = input->xmax + (10.0f * max_dim / 100.0f);
    newInput.xmin = input->xmin - (10.0f * max_dim / 100.0f);
    newInput.ymax = input->ymax + (10.0f * max_dim / 100.0f);
    newInput.ymin = input->ymin - (10.0f * max_dim / 100.0f);
  }

  NodeOperation *operation = getInputOperation(1);
  bokehInput.xmax = operation->getWidth();
  bokehInput.xmin = 0;
  bokehInput.ymax = operation->getHeight();
  bokehInput.ymin = 0;
  if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) {
    return true;
  }
  operation = getInputOperation(0);
  if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
    return true;
  }
  operation = getInputOperation(2);
  if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
    return true;
  }
  if (!this->m_sizeavailable) {
    rcti sizeInput;
    sizeInput.xmin = 0;
    sizeInput.ymin = 0;
    sizeInput.xmax = 5;
    sizeInput.ymax = 5;
    operation = getInputOperation(3);
    if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
      return true;
    }
  }
  return false;
}
bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	for (int i = 0; i < 4; ++i)
		if (getInputOperation(i + 1)->determineDependingAreaOfInterest(input, readOperation, output))
			return true;
	
	/* XXX this is bad, but unavoidable with the current design:
	 * we don't know the actual corners and matrix at this point,
	 * so all we can do is get the full input image
	 */
	output->xmin = 0;
	output->ymin = 0;
	output->xmax = getInputOperation(0)->getWidth();
	output->ymax = getInputOperation(0)->getHeight();
	return true;
//	return PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(input, readOperation, output);
}
bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti newInput;
	rcti bokehInput;

	const float max_dim = max(m_width, m_height);
	const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
	int maxBlurScalar = this->m_maxBlur * scalar;

	newInput.xmax = input->xmax + maxBlurScalar + 2;
	newInput.xmin = input->xmin - maxBlurScalar + 2;
	newInput.ymax = input->ymax + maxBlurScalar - 2;
	newInput.ymin = input->ymin - maxBlurScalar - 2;
	bokehInput.xmax = COM_BLUR_BOKEH_PIXELS;
	bokehInput.xmin = 0;
	bokehInput.ymax = COM_BLUR_BOKEH_PIXELS;
	bokehInput.ymin = 0;
	

	NodeOperation *operation = getInputOperation(2);
	if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
		return true;
	}
	operation = getInputOperation(1);
	if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output) ) {
		return true;
	}
#ifdef COM_DEFOCUS_SEARCH
	rcti searchInput;
	searchInput.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1;
	searchInput.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1;
	searchInput.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1;
	searchInput.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1;
	operation = getInputOperation(3);
	if (operation->determineDependingAreaOfInterest(&searchInput, readOperation, output) ) {
		return true;
	}
#endif
	operation = getInputOperation(0);
	if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
		return true;
	}
	return false;
}
void *GaussianAlphaYBlurOperation::initializeTileData(rcti *rect)
{
	lockMutex();
	if (!this->m_sizeavailable) {
		updateGauss();
	}
	void *buffer = getInputOperation(0)->initializeTileData(NULL);
	unlockMutex();
	return buffer;
}
void *BokehBlurOperation::initializeTileData(rcti * /*rect*/)
{
  lockMutex();
  if (!this->m_sizeavailable) {
    updateSize();
  }
  void *buffer = getInputOperation(0)->initializeTileData(NULL);
  unlockMutex();
  return buffer;
}
bool AntiAliasOperation::determineDependingAreaOfInterest(
        rcti *input,
        ReadBufferOperation *readOperation,
        rcti *output)
{
	rcti imageInput;
	NodeOperation *operation = getInputOperation(0);
	imageInput.xmax = input->xmax + 1;
	imageInput.xmin = input->xmin - 1;
	imageInput.ymax = input->ymax + 1;
	imageInput.ymin = input->ymin - 1;
	return operation->determineDependingAreaOfInterest(&imageInput,
	                                                   readOperation,
	                                                   output);
}
bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti imageInput;
	if (this->m_buffer) {
		return false;
	}
	else {
		NodeOperation *operation = getInputOperation(0);
		imageInput.xmax = operation->getWidth();
		imageInput.xmin = 0;
		imageInput.ymax = operation->getHeight();
		imageInput.ymin = 0;
		if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output) ) {
			return true;
		}
	}
	return false;
}
void *SunBeamsOperation::initializeTileData(rcti *rect)
{
	void *buffer = getInputOperation(0)->initializeTileData(NULL);
	return buffer;
}
bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti newInputValue;
	newInputValue.xmin = 0;
	newInputValue.ymin = 0;
	newInputValue.xmax = 2;
	newInputValue.ymax = 2;
	
	NodeOperation *operation = getInputOperation(1);
	if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output) ) {
		return true;
	}

	operation = getInputOperation(2);
	if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output) ) {
		return true;
	}
	
	/* XXX the original method of estimating the area-of-interest does not work
	 * it assumes a linear increase/decrease of mapped coordinates, which does not
	 * yield correct results for the area and leaves uninitialized buffer areas.
	 * So now just use the full image area, which may not be as efficient but works at least ...
	 */
#if 1
	rcti imageInput;
	
	operation = getInputOperation(0);
	imageInput.xmax = operation->getWidth();
	imageInput.xmin = 0;
	imageInput.ymax = operation->getHeight();
	imageInput.ymin = 0;

	if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output) ) {
		return true;
	}
	return false;
#else
	rcti newInput;
	const float margin = 2;
	
	BLI_rcti_init_minmax(&newInput);
	
	if (m_dispersion_const && m_distortion_const) {
		/* update from fixed distortion/dispersion */
#define UPDATE_INPUT(x, y) \
		{ \
			float coords[6]; \
			determineUV(coords, x, y); \
			newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
			newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
			newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
			newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
		} (void)0

		UPDATE_INPUT(input->xmin, input->xmax);
		UPDATE_INPUT(input->xmin, input->ymax);
		UPDATE_INPUT(input->xmax, input->ymax);
		UPDATE_INPUT(input->xmax, input->ymin);

#undef UPDATE_INPUT
	}
	else {
		/* use maximum dispersion 1.0 if not const */
		float dispersion = m_dispersion_const ? m_dispersion : 1.0f;

#define UPDATE_INPUT(x, y, distortion) \
		{ \
			float coords[6]; \
			updateVariables(distortion, dispersion); \
			determineUV(coords, x, y); \
			newInput.xmin = min_ffff(newInput.xmin, coords[0], coords[2], coords[4]); \
			newInput.ymin = min_ffff(newInput.ymin, coords[1], coords[3], coords[5]); \
			newInput.xmax = max_ffff(newInput.xmax, coords[0], coords[2], coords[4]); \
			newInput.ymax = max_ffff(newInput.ymax, coords[1], coords[3], coords[5]); \
		} (void)0
		
		if (m_distortion_const) {
			/* update from fixed distortion */
			UPDATE_INPUT(input->xmin, input->xmax, m_distortion);
			UPDATE_INPUT(input->xmin, input->ymax, m_distortion);
			UPDATE_INPUT(input->xmax, input->ymax, m_distortion);
			UPDATE_INPUT(input->xmax, input->ymin, m_distortion);
		}
		else {
			/* update from min/max distortion (-1..1) */
			UPDATE_INPUT(input->xmin, input->xmax, -1.0f);
			UPDATE_INPUT(input->xmin, input->ymax, -1.0f);
			UPDATE_INPUT(input->xmax, input->ymax, -1.0f);
			UPDATE_INPUT(input->xmax, input->ymin, -1.0f);

			UPDATE_INPUT(input->xmin, input->xmax, 1.0f);
			UPDATE_INPUT(input->xmin, input->ymax, 1.0f);
			UPDATE_INPUT(input->xmax, input->ymax, 1.0f);
			UPDATE_INPUT(input->xmax, input->ymin, 1.0f);

#undef UPDATE_INPUT
		}
	}

	newInput.xmin -= margin;
	newInput.ymin -= margin;
	newInput.xmax += margin;
	newInput.ymax += margin;

	operation = getInputOperation(0);
	if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
		return true;
	}
	return false;
#endif
}
void *KeyingClipOperation::initializeTileData(rcti *rect)
{
	void *buffer = getInputOperation(0)->initializeTileData(rect);

	return buffer;
}
void *AntiAliasOperation::initializeTileData(rcti *rect)
{
	return getInputOperation(0)->initializeTileData(rect);
}