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); } } }
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; }