void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
{
	MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer();
	float *buffer = memoryBuffer->getBuffer();
	if (this->m_input->isComplex()) {
		void *data = this->m_input->initializeTileData(rect);
		int x1 = rect->xmin;
		int y1 = rect->ymin;
		int x2 = rect->xmax;
		int y2 = rect->ymax;
		int x;
		int y;
		bool breaked = false;
		for (y = y1; y < y2 && (!breaked); y++) {
			int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
			for (x = x1; x < x2; x++) {
				this->m_input->read(&(buffer[offset4]), x, y, data);
				offset4 += COM_NUMBER_OF_CHANNELS;
			}
			if (isBreaked()) {
				breaked = true;
			}

		}
		if (data) {
			this->m_input->deinitializeTileData(rect, data);
			data = NULL;
		}
	}
	else {
		int x1 = rect->xmin;
		int y1 = rect->ymin;
		int x2 = rect->xmax;
		int y2 = rect->ymax;

		int x;
		int y;
		bool breaked = false;
		for (y = y1; y < y2 && (!breaked); y++) {
			int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
			for (x = x1; x < x2; x++) {
				this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST);
				offset4 += COM_NUMBER_OF_CHANNELS;
			}
			if (isBreaked()) {
				breaked = true;
			}
		}
	}
	memoryBuffer->setCreatedState();
}
void CompositorOperation::deinitExecution()
{
	if (!this->m_active)
		return;

	if (!isBreaked()) {
		Render *re = RE_GetRender(this->m_sceneName);
		RenderResult *rr = RE_AcquireResultWrite(re);

		if (rr) {
			if (rr->rectf != NULL) {
				MEM_freeN(rr->rectf);
			}
			rr->rectf = this->m_outputBuffer;
			if (rr->rectz != NULL) {
				MEM_freeN(rr->rectz);
			}
			rr->rectz = this->m_depthBuffer;
		}
		else {
			if (this->m_outputBuffer) {
				MEM_freeN(this->m_outputBuffer);
			}
			if (this->m_depthBuffer) {
				MEM_freeN(this->m_depthBuffer);
			}
		}

		if (re) {
			RE_ReleaseResult(re);
			re = NULL;
		}

		BLI_lock_thread(LOCK_DRAW_IMAGE);
		BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE);
		BLI_unlock_thread(LOCK_DRAW_IMAGE);
	}
	else {
		if (this->m_outputBuffer) {
			MEM_freeN(this->m_outputBuffer);
		}
		if (this->m_depthBuffer) {
			MEM_freeN(this->m_depthBuffer);
		}
	}

	this->m_outputBuffer = NULL;
	this->m_depthBuffer = NULL;
	this->m_imageInput = NULL;
	this->m_alphaInput = NULL;
	this->m_depthInput = NULL;
}
void ViewerOperation::executeRegion(rcti *rect, unsigned int tileNumber)
{
	float *buffer = this->m_outputBuffer;
	float *depthbuffer = this->m_depthBuffer;
	if (!buffer) return;
	const int x1 = rect->xmin;
	const int y1 = rect->ymin;
	const int x2 = rect->xmax;
	const int y2 = rect->ymax;
	const int offsetadd = (this->getWidth() - (x2 - x1));
	const int offsetadd4 = offsetadd * 4;
	int offset = (y1 * this->getWidth() + x1);
	int offset4 = offset * 4;
	float alpha[4], depth[4];
	int x;
	int y;
	bool breaked = false;

	for (y = y1; y < y2 && (!breaked); y++) {
		for (x = x1; x < x2; x++) {
			this->m_imageInput->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST);
			if (this->m_ignoreAlpha) {
				buffer[offset4 + 3] = 1.0f;
			}
			else {
				if (this->m_alphaInput != NULL) {
					this->m_alphaInput->readSampled(alpha, x, y, COM_PS_NEAREST);
					buffer[offset4 + 3] = alpha[0];
				}
			}
			if (m_depthInput) {
				this->m_depthInput->readSampled(depth, x, y, COM_PS_NEAREST);
				depthbuffer[offset] = depth[0];
			}

			offset ++;
			offset4 += 4;
		}
		if (isBreaked()) {
			breaked = true;
		}
		offset += offsetadd;
		offset4 += offsetadd4;
	}
	updateImage(rect);
}
void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings)
{
	const int qt = 1 << settings->quality;
	const float s1 = 4.0f / (float)qt, s2 = 2.0f * s1;
	int x, y, n, p, np;
	fRGB c, tc, cm[64];
	float sc, isc, u, v, sm, s, t, ofs, scalef[64];
	const float cmo = 1.0f - settings->colmod;

	MemoryBuffer *gbuf = inputTile->duplicate();
	MemoryBuffer *tbuf1 = inputTile->duplicate();

	bool breaked = false;

	FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 0, 3);
	if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 1, 3);
	if (isBreaked()) breaked = true;
	if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf1, s1, 2, 3);

	MemoryBuffer *tbuf2 = tbuf1->duplicate();

	if (isBreaked()) breaked = true;
	if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 0, 3);
	if (isBreaked()) breaked = true;
	if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 1, 3);
	if (isBreaked()) breaked = true;
	if (!breaked) FastGaussianBlurOperation::IIR_gauss(tbuf2, s2, 2, 3);

	ofs = (settings->iter & 1) ? 0.5f : 0.0f;
	for (x = 0; x < (settings->iter * 4); x++) {
		y = x & 3;
		cm[x][0] = cm[x][1] = cm[x][2] = 1;
		if (y == 1) fRGB_rgbmult(cm[x], 1.0f, cmo, cmo);
		if (y == 2) fRGB_rgbmult(cm[x], cmo, cmo, 1.0f);
		if (y == 3) fRGB_rgbmult(cm[x], cmo, 1.0f, cmo);
		scalef[x] = 2.1f * (1.0f - (x + ofs) / (float)(settings->iter * 4));
		if (x & 1) scalef[x] = -0.99f / scalef[x];
	}

	sc = 2.13;
	isc = -0.97;
	for (y = 0; y < gbuf->getHeight() && (!breaked); y++) {
		v = ((float)y + 0.5f) / (float)gbuf->getHeight();
		for (x = 0; x < gbuf->getWidth(); x++) {
			u = ((float)x + 0.5f) / (float)gbuf->getWidth();
			s = (u - 0.5f) * sc + 0.5f, t = (v - 0.5f) * sc + 0.5f;
			tbuf1->readBilinear(c, s * gbuf->getWidth(), t * gbuf->getHeight());
			sm = smoothMask(s, t);
			mul_v3_fl(c, sm);
			s = (u - 0.5f) * isc + 0.5f, t = (v - 0.5f) * isc + 0.5f;
			tbuf2->readBilinear(tc, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f);
			sm = smoothMask(s, t);
			madd_v3_v3fl(c, tc, sm);

			gbuf->writePixel(x, y, c);
		}
		if (isBreaked()) breaked = true;

	}

	memset(tbuf1->getBuffer(), 0, tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));
	for (n = 1; n < settings->iter && (!breaked); n++) {
		for (y = 0; y < gbuf->getHeight() && (!breaked); y++) {
			v = ((float)y + 0.5f) / (float)gbuf->getHeight();
			for (x = 0; x < gbuf->getWidth(); x++) {
				u = ((float)x + 0.5f) / (float)gbuf->getWidth();
				tc[0] = tc[1] = tc[2] = 0.0f;
				for (p = 0; p < 4; p++) {
					np = (n << 2) + p;
					s = (u - 0.5f) * scalef[np] + 0.5f;
					t = (v - 0.5f) * scalef[np] + 0.5f;
					gbuf->readBilinear(c, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f);
					mul_v3_v3(c, cm[np]);
					sm = smoothMask(s, t) * 0.25f;
					madd_v3_v3fl(tc, c, sm);
				}
				tbuf1->addPixel(x, y, tc);
			}
			if (isBreaked()) breaked = true;
		}
		memcpy(gbuf->getBuffer(), tbuf1->getBuffer(), tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));
	}
	memcpy(data, gbuf->getBuffer(), gbuf->getWidth() * gbuf->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));

	delete gbuf;
	delete tbuf1;
	delete tbuf2;
}
void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber)
{
	float color[8]; // 7 is enough
	float *buffer = this->m_outputBuffer;
	float *zbuffer = this->m_depthBuffer;

	if (!buffer) return;
	int x1 = rect->xmin;
	int y1 = rect->ymin;
	int x2 = rect->xmax;
	int y2 = rect->ymax;
	int offset = (y1 * this->getWidth() + x1);
	int add = (this->getWidth() - (x2 - x1));
	int offset4 = offset * COM_NUMBER_OF_CHANNELS;
	int x;
	int y;
	bool breaked = false;
	int dx = 0, dy = 0;

#if 0
	const RenderData *rd = this->m_rd;

	if (rd->mode & R_BORDER && rd->mode & R_CROP) {
	/*!
	   When using cropped render result, need to re-position area of interest,
	   so it'll natch bounds of render border within frame. By default, canvas
	   will be centered between full frame and cropped frame, so we use such
	   scheme to map cropped coordinates to full-frame coordinates

		   ^ Y
		   |                      Width
		   +------------------------------------------------+
		   |                                                |
		   |                                                |
		   |  Centered canvas, we map coordinate from it    |
		   |              +------------------+              |
		   |              |                  |              |  H
		   |              |                  |              |  e
		   |  +------------------+ . Center  |              |  i
		   |  |           |      |           |              |  g
		   |  |           |      |           |              |  h
		   |  |....dx.... +------|-----------+              |  t
		   |  |           . dy   |                          |
		   |  +------------------+                          |
		   |  Render border, we map coordinates to it       |
		   |                                                |    X
		   +------------------------------------------------+---->
		                        Full frame
		 */

		int full_width  = rd->xsch * rd->size / 100;
		int full_height = rd->ysch * rd->size / 100;

		dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f;
		dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f;
	}
#endif

	for (y = y1; y < y2 && (!breaked); y++) {
		for (x = x1; x < x2 && (!breaked); x++) {
			int input_x = x + dx, input_y = y + dy;

			this->m_imageInput->readSampled(color, input_x, input_y, COM_PS_NEAREST);
			if (this->m_ignoreAlpha) {
				color[3] = 1.0f;
			}
			else {
				if (this->m_alphaInput != NULL) {
					this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, COM_PS_NEAREST);
				}
			}

			copy_v4_v4(buffer + offset4, color);

			if (this->m_depthInput != NULL) {
				this->m_depthInput->readSampled(color, input_x, input_y, COM_PS_NEAREST);
				zbuffer[offset] = color[0];
			}
			offset4 += COM_NUMBER_OF_CHANNELS;
			offset++;
			if (isBreaked()) {
				breaked = true;
			}
		}
		offset += add;
		offset4 += add * COM_NUMBER_OF_CHANNELS;
	}
}
void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings)
{
	int x, y, n;
	unsigned int nump = 0;
	float c1[4], c2[4], c3[4], c4[4];
	float a, ang = DEG2RADF(360.0f) / (float)settings->streaks;

	int size = inputTile->getWidth() * inputTile->getHeight();
	int size4 = size * 4;

	bool breaked = false;

	MemoryBuffer *tsrc = inputTile->duplicate();
	MemoryBuffer *tdst = new MemoryBuffer(COM_DT_COLOR, inputTile->getRect());
	tdst->clear();
	memset(data, 0, size4 * sizeof(float));

	for (a = 0.0f; a < DEG2RADF(360.0f) && (!breaked); a += ang) {
		const float an = a + settings->angle_ofs;
		const float vx = cos((double)an), vy = sin((double)an);
		for (n = 0; n < settings->iter && (!breaked); ++n) {
			const float p4 = pow(4.0, (double)n);
			const float vxp = vx * p4, vyp = vy * p4;
			const float wt = pow((double)settings->fade, (double)p4);
			const float cmo = 1.0f - (float)pow((double)settings->colmod, (double)n + 1);  // colormodulation amount relative to current pass
			float *tdstcol = tdst->getBuffer();
			for (y = 0; y < tsrc->getHeight() && (!breaked); ++y) {
				for (x = 0; x < tsrc->getWidth(); ++x, tdstcol += 4) {
					// first pass no offset, always same for every pass, exact copy,
					// otherwise results in uneven brightness, only need once
					if (n == 0) tsrc->read(c1, x, y); else c1[0] = c1[1] = c1[2] = 0;
					tsrc->readBilinear(c2, x + vxp, y + vyp);
					tsrc->readBilinear(c3, x + vxp * 2.0f, y + vyp * 2.0f);
					tsrc->readBilinear(c4, x + vxp * 3.0f, y + vyp * 3.0f);
					// modulate color to look vaguely similar to a color spectrum
					c2[1] *= cmo;
					c2[2] *= cmo;

					c3[0] *= cmo;
					c3[1] *= cmo;

					c4[0] *= cmo;
					c4[2] *= cmo;

					tdstcol[0] = 0.5f * (tdstcol[0] + c1[0] + wt * (c2[0] + wt * (c3[0] + wt * c4[0])));
					tdstcol[1] = 0.5f * (tdstcol[1] + c1[1] + wt * (c2[1] + wt * (c3[1] + wt * c4[1])));
					tdstcol[2] = 0.5f * (tdstcol[2] + c1[2] + wt * (c2[2] + wt * (c3[2] + wt * c4[2])));
					tdstcol[3] = 1.0f;
				}
				if (isBreaked()) {
					breaked = true;
				}
			}
			memcpy(tsrc->getBuffer(), tdst->getBuffer(), sizeof(float) * size4);
		}

		float *sourcebuffer = tsrc->getBuffer();
		float factor = 1.0f / (float)(6 - settings->iter);
		for (int i = 0; i < size4; i += 4) {
			madd_v3_v3fl(&data[i], &sourcebuffer[i], factor);
			data[i + 3] =  1.0f;
		}

		tdst->clear();
		memcpy(tsrc->getBuffer(), inputTile->getBuffer(), sizeof(float) * size4);
		nump++;
	}

	delete tsrc;
	delete tdst;
}