void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect)
{
	lockMutex();
	if (!this->m_iirgaus) {
		MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputprogram->initializeTileData(rect);
		MemoryBuffer *copy = newBuf->duplicate();
		FastGaussianBlurOperation::IIR_gauss(copy, this->m_sigma, 0, 3);

		if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) {
			float *src = newBuf->getBuffer();
			float *dst = copy->getBuffer();
			for (int i = copy->getWidth() * copy->getHeight(); i != 0; i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) {
				if (*src < *dst) {
					*dst = *src;
				}
			}
		}
		else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) {
			float *src = newBuf->getBuffer();
			float *dst = copy->getBuffer();
			for (int i = copy->getWidth() * copy->getHeight(); i != 0; i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) {
				if (*src > *dst) {
					*dst = *src;
				}
			}
		}

//		newBuf->

		this->m_iirgaus = copy;
	}
	unlockMutex();
	return this->m_iirgaus;
}
cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex,
                                                               list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers,
                                                               ReadBufferOperation *reader)
{
	cl_int error;
	
	MemoryBuffer *result = reader->getInputMemoryBuffer(inputMemoryBuffers);

	const cl_image_format imageFormat = {
		CL_RGBA,
		CL_FLOAT
	};

	cl_mem clBuffer = clCreateImage2D(this->m_context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, &imageFormat, result->getWidth(),
	                                  result->getHeight(), 0, result->getBuffer(), &error);

	if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
	if (error == CL_SUCCESS) cleanup->push_back(clBuffer);

	error = clSetKernelArg(kernel, parameterIndex, sizeof(cl_mem), &clBuffer);
	if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }

	COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, offsetIndex, result);
	return clBuffer;
}
void KeyingClipOperation::executePixel(float *color, int x, int y, void *data)
{
	const int delta = this->m_kernelRadius;
	const float tolerance = this->m_kernelTolerance;

	MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
	float *buffer = inputBuffer->getBuffer();

	int bufferWidth = inputBuffer->getWidth();
	int bufferHeight = inputBuffer->getHeight();

	int i, j, count = 0, totalCount = 0;

	float value = buffer[(y * bufferWidth + x) * 4];

	bool ok = false;

	for (i = -delta + 1; i < delta; i++) {
		for (j = -delta + 1; j < delta; j++) {
			int cx = x + j, cy = y + i;

			if (i == 0 && j == 0)
				continue;

			if (cx >= 0 && cx < bufferWidth && cy >= 0 && cy < bufferHeight) {
				int bufferIndex = (cy * bufferWidth + cx) * 4;
				float currentValue = buffer[bufferIndex];

				if (fabsf(currentValue - value) < tolerance) {
					count++;
				}

				totalCount++;
			}
		}
	}

	ok = count >= (float) totalCount * 0.9f;

	if (this->m_isEdgeMatte) {
		if (ok)
			color[0] = 0.0f;
		else
			color[0] = 1.0f;
	}
	else {
		color[0] = value;

		if (ok) {
			if (color[0] < this->m_clipBlack)
				color[0] = 0.0f;
			else if (color[0] >= this->m_clipWhite)
				color[0] = 1.0f;
			else
				color[0] = (color[0] - this->m_clipBlack) / (this->m_clipWhite - this->m_clipBlack);
		}
	}
}
void *AntiAliasOperation::initializeTileData(rcti *rect)
{
	if (this->m_buffer) { return this->m_buffer; }
	lockMutex();
	if (this->m_buffer == NULL) {
		MemoryBuffer *tile = (MemoryBuffer *)this->m_valueReader->initializeTileData(rect);
		int size = tile->getHeight() * tile->getWidth();
		float *input = tile->getBuffer();
		char *valuebuffer = (char *)MEM_mallocN(sizeof(char) * size, __func__);
		for (int i = 0; i < size; i++) {
			float in = input[i * COM_NUMBER_OF_CHANNELS];
			valuebuffer[i] = FTOCHAR(in);
		}
		antialias_tagbuf(tile->getWidth(), tile->getHeight(), valuebuffer);
		this->m_buffer = valuebuffer;
	}
	unlockMutex();
	return this->m_buffer;
}
void *ErodeStepOperation::initializeTileData(rcti *rect)
{
	if (this->m_cached_buffer != NULL) {
		return this->m_cached_buffer;
	}
	lockMutex();
	if (this->m_cached_buffer == NULL) {
		MemoryBuffer *buffer = (MemoryBuffer *)this->m_inputProgram->initializeTileData(NULL);
		float *rectf = buffer->convertToValueBuffer();
		int x, y, i;
		float *p;
		int bwidth = buffer->getWidth();
		int bheight = buffer->getHeight();
		for (i = 0; i < this->m_iterations; i++) {
			for (y = 0; y < bheight; y++) {
				for (x = 0; x < bwidth - 1; x++) {
					p = rectf + (bwidth * y + x);
					*p = MIN2(*p, *(p + 1));
				}
			}
		
			for (y = 0; y < bheight; y++) {
				for (x = bwidth - 1; x >= 1; x--) {
					p = rectf + (bwidth * y + x);
					*p = MIN2(*p, *(p - 1));
				}
			}
		
			for (x = 0; x < bwidth; x++) {
				for (y = 0; y < bheight - 1; y++) {
					p = rectf + (bwidth * y + x);
					*p = MIN2(*p, *(p + bwidth));
				}
			}
		
			for (x = 0; x < bwidth; x++) {
				for (y = bheight - 1; y >= 1; y--) {
					p = rectf + (bwidth * y + x);
					*p = MIN2(*p, *(p - bwidth));
				}
			}
		}
		this->m_cached_buffer = rectf;
	}
	unlockMutex();
	return this->m_cached_buffer;
}
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 KeyingClipOperation::executePixel(float output[4], int x, int y, void *data)
{
	const int delta = this->m_kernelRadius;
	const float tolerance = this->m_kernelTolerance;

	MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
	float *buffer = inputBuffer->getBuffer();

	int bufferWidth = inputBuffer->getWidth();
	int bufferHeight = inputBuffer->getHeight();

	float value = buffer[(y * bufferWidth + x) * 4];

	bool ok = false;
	int start_x = max_ff(0, x - delta + 1),
	    start_y = max_ff(0, y - delta + 1),
	    end_x = min_ff(x + delta - 1, bufferWidth - 1),
	    end_y = min_ff(y + delta - 1, bufferHeight - 1);

	int count = 0, totalCount = (end_x - start_x + 1) * (end_y - start_y + 1) - 1;
	int thresholdCount = ceil((float) totalCount * 0.9f);

	if (delta == 0) {
		ok = true;
	}

	for (int cx = start_x; ok == false && cx <= end_x; ++cx) {
		for (int cy = start_y; ok == false && cy <= end_y; ++cy) {
			if (UNLIKELY(cx == x && cy == y)) {
				continue;
			}

			int bufferIndex = (cy * bufferWidth + cx) * 4;
			float currentValue = buffer[bufferIndex];

			if (fabsf(currentValue - value) < tolerance) {
				count++;
				if (count >= thresholdCount) {
					ok = true;
				}
			}
		}
	}

	if (this->m_isEdgeMatte) {
		if (ok)
			output[0] = 0.0f;
		else
			output[0] = 1.0f;
	}
	else {
		output[0] = value;

		if (ok) {
			if (output[0] < this->m_clipBlack)
				output[0] = 0.0f;
			else if (output[0] >= this->m_clipWhite)
				output[0] = 1.0f;
			else
				output[0] = (output[0] - this->m_clipBlack) / (this->m_clipWhite - this->m_clipBlack);
		}
	}
}
void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
{
	VariableSizeBokehBlurTileData *tileData = (VariableSizeBokehBlurTileData *)data;
	MemoryBuffer *inputProgramBuffer = tileData->color;
	MemoryBuffer *inputBokehBuffer = tileData->bokeh;
	MemoryBuffer *inputSizeBuffer = tileData->size;
	float *inputSizeFloatBuffer = inputSizeBuffer->getBuffer();
	float *inputProgramFloatBuffer = inputProgramBuffer->getBuffer();
	float readColor[4];
	float bokeh[4];
	float tempSize[4];
	float multiplier_accum[4];
	float color_accum[4];

	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 = tileData->maxBlurScalar;

	BLI_assert(inputBokehBuffer->getWidth()  == COM_BLUR_BOKEH_PIXELS);
	BLI_assert(inputBokehBuffer->getHeight() == COM_BLUR_BOKEH_PIXELS);

#ifdef COM_DEFOCUS_SEARCH
	float search[4];
	this->m_inputSearchProgram->read(search, x / InverseSearchRadiusOperation::DIVIDER, y / InverseSearchRadiusOperation::DIVIDER, NULL);
	int minx = search[0];
	int miny = search[1];
	int maxx = search[2];
	int maxy = search[3];
#else
	int minx = max(x - maxBlurScalar, 0);
	int miny = max(y - maxBlurScalar, 0);
	int maxx = min(x + maxBlurScalar, (int)m_width);
	int maxy = min(y + maxBlurScalar, (int)m_height);
#endif
	{
		inputSizeBuffer->readNoCheck(tempSize, x, y);
		inputProgramBuffer->readNoCheck(readColor, x, y);

		copy_v4_v4(color_accum, readColor);
		copy_v4_fl(multiplier_accum, 1.0f);
		float size_center = tempSize[0] * scalar;
		
		const int addXStepValue = QualityStepHelper::getStep();
		const int addYStepValue = addXStepValue;
		const int addXStepColor = addXStepValue * COM_NUM_CHANNELS_COLOR;

		if (size_center > this->m_threshold) {
			for (int ny = miny; ny < maxy; ny += addYStepValue) {
				float dy = ny - y;
				int offsetValueNy = ny * inputSizeBuffer->getWidth();
				int offsetValueNxNy = offsetValueNy + (minx);
				int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR;
				for (int nx = minx; nx < maxx; nx += addXStepValue) {
					if (nx != x || ny != y) {
						float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
						if (size > this->m_threshold) {
							float dx = nx - x;
							if (size > fabsf(dx) && size > fabsf(dy)) {
								float uv[2] = {
									(float)(COM_BLUR_BOKEH_PIXELS / 2) + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1),
									(float)(COM_BLUR_BOKEH_PIXELS / 2) + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1)};
								inputBokehBuffer->read(bokeh, uv[0], uv[1]);
								madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetColorNxNy]);
								add_v4_v4(multiplier_accum, bokeh);
							}
						}
					}
					offsetColorNxNy += addXStepColor;
					offsetValueNxNy += addXStepValue;				}
			}
		}

		output[0] = color_accum[0] / multiplier_accum[0];
		output[1] = color_accum[1] / multiplier_accum[1];
		output[2] = color_accum[2] / multiplier_accum[2];
		output[3] = color_accum[3] / multiplier_accum[3];

		/* blend in out values over the threshold, otherwise we get sharp, ugly transitions */
		if ((size_center > this->m_threshold) &&
		    (size_center < this->m_threshold * 2.0f))
		{
			/* factor from 0-1 */
			float fac = (size_center - this->m_threshold) / this->m_threshold;
			interp_v4_v4v4(output, readColor, output, fac);
		}
	}

}
Exemple #9
0
void *ErodeStepOperation::initializeTileData(rcti *rect)
{
    MemoryBuffer *tile = (MemoryBuffer *)this->m_inputProgram->initializeTileData(NULL);
    int x, y, i;
    int width = tile->getWidth();
    int height = tile->getHeight();
    float *buffer = tile->getBuffer();

    int half_window = this->m_iterations;
    int window = half_window * 2 + 1;

    int xmin = max(0, rect->xmin - half_window);
    int ymin = max(0, rect->ymin - half_window);
    int xmax = min(width,  rect->xmax + half_window);
    int ymax = min(height, rect->ymax + half_window);

    int bwidth = rect->xmax - rect->xmin;
    int bheight = rect->ymax - rect->ymin;

    // Note: Cache buffer has original tilesize width, but new height.
    // We have to calculate the additional rows in the first pass,
    // to have valid data available for the second pass.
    tile_info *result = create_cache(rect->xmin, rect->xmax, ymin, ymax);
    float *rectf = result->buffer;

    // temp holds maxima for every step in the algorithm, buf holds a
    // single row or column of input values, padded with MAXFLOATs to
    // simplify the logic.
    float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
    float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), "dilate erode buf");

    // The following is based on the van Herk/Gil-Werman algorithm for morphology operations.
    // first pass, horizontal dilate/erode
    for (y = ymin; y < ymax; y++) {
        for (x = 0; x < bwidth + 5 * half_window; x++) {
            buf[x] = MAXFLOAT;
        }
        for (x = xmin; x < xmax; ++x) {
            buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)];
        }

        for (i = 0; i < (bwidth + 3 * half_window) / window; i++) {
            int start = (i + 1) * window - 1;

            temp[window - 1] = buf[start];
            for (x = 1; x < window; x++) {
                temp[window - 1 - x] = min(temp[window - x], buf[start - x]);
                temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]);
            }

            start = half_window + (i - 1) * window + 1;
            for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) {
                rectf[bwidth * (y - ymin) + (start + x)] = min(temp[x], temp[x + window - 1]);
            }
        }
    }

    // second pass, vertical dilate/erode
    for (x = 0; x < bwidth; x++) {
        for (y = 0; y < bheight + 5 * half_window; y++) {
            buf[y] = MAXFLOAT;
        }
        for (y = ymin; y < ymax; y++) {
            buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x];
        }

        for (i = 0; i < (bheight + 3 * half_window) / window; i++) {
            int start = (i + 1) * window - 1;

            temp[window - 1] = buf[start];
            for (y = 1; y < window; y++) {
                temp[window - 1 - y] = min(temp[window - y], buf[start - y]);
                temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]);
            }

            start = half_window + (i - 1) * window + 1;
            for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) {
                rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = min(temp[y], temp[y + window - 1]);
            }
        }
    }

    MEM_freeN(temp);
    MEM_freeN(buf);

    return result;
}
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;
}