| #include "iwa_bokehreffx.h" |
| |
| #include "trop.h" |
| |
| #include <QReadWriteLock> |
| #include <QSet> |
| #include <math.h> |
| |
| namespace { |
| QMutex fx_mutex; |
| QReadWriteLock lock; |
| |
| template <typename T> |
| TRasterGR8P allocateRasterAndLock(T** buf, TDimensionI dim) { |
| TRasterGR8P ras(dim.lx * sizeof(T), dim.ly); |
| ras->lock(); |
| *buf = (T*)ras->getRawData(); |
| return ras; |
| } |
| |
| |
| inline int getCoord(int index, int lx, int ly) { |
| int i = index % lx; |
| int j = index / lx; |
| |
| int cx = i - lx / 2; |
| int cy = j - ly / 2; |
| |
| if (cx < 0) cx += lx; |
| if (cy < 0) cy += ly; |
| |
| return cy * lx + cx; |
| } |
| |
| |
| void releaseAllRasters(QList<TRasterGR8P>& rasterList) { |
| for (int r = 0; r < rasterList.size(); r++) rasterList.at(r)->unlock(); |
| } |
| |
| |
| void releaseAllRastersAndPlans(QList<TRasterGR8P>& rasterList, |
| QList<kiss_fftnd_cfg>& planList) { |
| releaseAllRasters(rasterList); |
| for (int p = 0; p < planList.size(); p++) kiss_fft_free(planList.at(p)); |
| } |
| }; |
| |
| |
| BokehRefThread::BokehRefThread(int channel, kiss_fft_cpx* fftcpx_channel_before, |
| kiss_fft_cpx* fftcpx_channel, |
| kiss_fft_cpx* fftcpx_alpha, |
| kiss_fft_cpx* fftcpx_iris, float4* result_buff, |
| kiss_fftnd_cfg kissfft_plan_fwd, |
| kiss_fftnd_cfg kissfft_plan_bkwd, |
| TDimensionI& dim) |
| : m_channel(channel) |
| , m_fftcpx_channel_before(fftcpx_channel_before) |
| , m_fftcpx_channel(fftcpx_channel) |
| , m_fftcpx_alpha(fftcpx_alpha) |
| , m_fftcpx_iris(fftcpx_iris) |
| , m_result_buff(result_buff) |
| , m_kissfft_plan_fwd(kissfft_plan_fwd) |
| , m_kissfft_plan_bkwd(kissfft_plan_bkwd) |
| , m_dim(dim) |
| , m_finished(false) |
| , m_isTerminated(false) {} |
| |
| |
| |
| void BokehRefThread::run() { |
| |
| kiss_fftnd(m_kissfft_plan_fwd, m_fftcpx_channel_before, m_fftcpx_channel); |
| |
| |
| if (m_isTerminated) { |
| m_finished = true; |
| return; |
| } |
| |
| int size = m_dim.lx * m_dim.ly; |
| |
| |
| for (int i = 0; i < size; i++) { |
| float re, im; |
| re = m_fftcpx_channel[i].r * m_fftcpx_iris[i].r - |
| m_fftcpx_channel[i].i * m_fftcpx_iris[i].i; |
| im = m_fftcpx_channel[i].r * m_fftcpx_iris[i].i + |
| m_fftcpx_iris[i].r * m_fftcpx_channel[i].i; |
| m_fftcpx_channel[i].r = re; |
| m_fftcpx_channel[i].i = im; |
| } |
| |
| kiss_fftnd(m_kissfft_plan_bkwd, m_fftcpx_channel, m_fftcpx_channel_before); |
| |
| |
| if (m_isTerminated) { |
| m_finished = true; |
| return; |
| } |
| |
| |
| float4* result_p = m_result_buff; |
| for (int i = 0; i < size; i++, result_p++) { |
| |
| int coord = getCoord(i, m_dim.lx, m_dim.ly); |
| |
| float alpha = m_fftcpx_alpha[coord].r / (float)size; |
| |
| if (alpha == 0.0f) continue; |
| |
| float exposure = m_fftcpx_channel_before[coord].r / (float)size; |
| |
| |
| if (alpha >= 1.0f || (m_channel == 0 && (*result_p).x == 0.0f) || |
| (m_channel == 1 && (*result_p).y == 0.0f) || |
| (m_channel == 2 && (*result_p).z == 0.0f)) { |
| |
| if (m_channel == 0) |
| (*result_p).x = exposure; |
| else if (m_channel == 1) |
| (*result_p).y = exposure; |
| else |
| (*result_p).z = exposure; |
| } |
| |
| else { |
| if (m_channel == 0) |
| { |
| (*result_p).x *= 1.0f - alpha; |
| (*result_p).x += exposure; |
| } else if (m_channel == 1) |
| { |
| (*result_p).y *= 1.0f - alpha; |
| (*result_p).y += exposure; |
| } else |
| { |
| (*result_p).z *= 1.0f - alpha; |
| (*result_p).z += exposure; |
| } |
| } |
| } |
| m_finished = true; |
| } |
| |
| |
| |
| |
| |
| |
| float Iwa_BokehRefFx::getBokehPixelAmount(const double frame, |
| const TAffine affine) { |
| |
| TPointD vect; |
| vect.x = m_bokehAmount->getValue(frame); |
| vect.y = 0.0; |
| |
| TAffine aff(affine); |
| aff.a13 = aff.a23 = 0; |
| vect = aff * vect; |
| |
| return sqrtf((float)(vect.x * vect.x + vect.y * vect.y)); |
| } |
| |
| |
| |
| |
| |
| template <typename RASTER, typename PIXEL> |
| bool Iwa_BokehRefFx::setSourceRaster(const RASTER srcRas, float4* dstMem, |
| TDimensionI dim) { |
| bool isPremultiplied = true; |
| |
| float4* chann_p = dstMem; |
| for (int j = 0; j < dim.ly; j++) { |
| PIXEL* pix = srcRas->pixels(j); |
| for (int i = 0; i < dim.lx; i++, pix++, chann_p++) { |
| (*chann_p).x = (float)pix->r / (float)PIXEL::maxChannelValue; |
| (*chann_p).y = (float)pix->g / (float)PIXEL::maxChannelValue; |
| (*chann_p).z = (float)pix->b / (float)PIXEL::maxChannelValue; |
| (*chann_p).w = (float)pix->m / (float)PIXEL::maxChannelValue; |
| |
| |
| |
| |
| if (isPremultiplied && |
| ((*chann_p).x > (*chann_p).w || (*chann_p).y > (*chann_p).w || |
| (*chann_p).z > (*chann_p).w)) |
| isPremultiplied = false; |
| } |
| } |
| return isPremultiplied; |
| } |
| |
| |
| |
| |
| |
| template <typename RASTER, typename PIXEL> |
| void Iwa_BokehRefFx::setDepthRaster(const RASTER srcRas, unsigned char* dstMem, |
| TDimensionI dim) { |
| unsigned char* depth_p = dstMem; |
| for (int j = 0; j < dim.ly; j++) { |
| PIXEL* pix = srcRas->pixels(j); |
| for (int i = 0; i < dim.lx; i++, pix++, depth_p++) { |
| |
| float val = ((float)pix->r * 0.3f + (float)pix->g * 0.59f + |
| (float)pix->b * 0.11f) / |
| (float)PIXEL::maxChannelValue; |
| |
| (*depth_p) = (unsigned char)(val * (float)UCHAR_MAX + 0.5f); |
| } |
| } |
| } |
| |
| template <typename RASTER, typename PIXEL> |
| void Iwa_BokehRefFx::setDepthRasterGray(const RASTER srcRas, |
| unsigned char* dstMem, |
| TDimensionI dim) { |
| unsigned char* depth_p = dstMem; |
| for (int j = 0; j < dim.ly; j++) { |
| PIXEL* pix = srcRas->pixels(j); |
| for (int i = 0; i < dim.lx; i++, pix++, depth_p++) { |
| |
| float val = (float)pix->value / (float)PIXEL::maxChannelValue; |
| |
| (*depth_p) = (unsigned char)(val * (float)UCHAR_MAX + 0.5f); |
| } |
| } |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::defineSegemntDepth( |
| const unsigned char* indexMap_main, const unsigned char* indexMap_sub, |
| const float* mainSub_ratio, const unsigned char* depth_buff, |
| const TDimensionI& dimOut, const double frame, |
| QVector<float>& segmentDepth_main, QVector<float>& segmentDepth_sub) { |
| QSet<int> segmentValues; |
| |
| |
| struct HISTO { |
| int pix_amount; |
| int belongingSegmentValue; |
| int segmentId; |
| int segmentId_sub; |
| } histo[256]; |
| |
| |
| for (int h = 0; h < 256; h++) { |
| histo[h].pix_amount = 0; |
| histo[h].belongingSegmentValue = -1; |
| histo[h].segmentId = -1; |
| } |
| |
| int size = dimOut.lx * dimOut.ly; |
| |
| |
| int minHisto = (int)UCHAR_MAX; |
| int maxHisto = 0; |
| |
| unsigned char* depth_p = (unsigned char*)depth_buff; |
| for (int i = 0; i < size; i++, depth_p++) { |
| histo[(int)*depth_p].pix_amount++; |
| |
| if ((int)*depth_p < minHisto) minHisto = (int)*depth_p; |
| if ((int)*depth_p > maxHisto) maxHisto = (int)*depth_p; |
| } |
| |
| |
| segmentValues.insert(minHisto); |
| segmentValues.insert(maxHisto); |
| |
| |
| int focusVal = (int)(m_onFocusDistance->getValue(frame) * (double)UCHAR_MAX); |
| if (minHisto < focusVal && focusVal < maxHisto) |
| segmentValues.insert(focusVal); |
| |
| |
| for (int h = 0; h < 256; h++) { |
| for (int seg = 0; seg < segmentValues.size(); seg++) { |
| |
| if (histo[h].belongingSegmentValue == -1) { |
| histo[h].belongingSegmentValue = segmentValues.values().at(seg); |
| continue; |
| } |
| |
| int tmpError = std::abs(h - histo[h].belongingSegmentValue); |
| if (tmpError == 0) break; |
| |
| int newError = std::abs(h - segmentValues.values().at(seg)); |
| |
| if (newError < tmpError) |
| histo[h].belongingSegmentValue = segmentValues.values().at(seg); |
| } |
| } |
| |
| |
| while (segmentValues.size() < m_distancePrecision->getValue()) { |
| |
| |
| double tmpMaxErrorMod = 0; |
| int tmpBestNewSegVal; |
| bool newSegFound = false; |
| for (int h = minHisto + 1; h < maxHisto; h++) { |
| |
| if (histo[h].belongingSegmentValue == h) continue; |
| |
| double errorModAmount = 0; |
| |
| |
| for (int i = minHisto + 1; i < maxHisto; i++) { |
| |
| |
| |
| if (std::abs(i - histo[i].belongingSegmentValue) > |
| std::abs(i - h)) |
| |
| errorModAmount += |
| (std::abs(i - histo[i].belongingSegmentValue) - std::abs(i - h)) * |
| histo[i].pix_amount; |
| } |
| |
| |
| if (errorModAmount > tmpMaxErrorMod) { |
| tmpMaxErrorMod = errorModAmount; |
| tmpBestNewSegVal = h; |
| newSegFound = true; |
| } |
| } |
| |
| if (!newSegFound) break; |
| |
| |
| segmentValues.insert(tmpBestNewSegVal); |
| |
| |
| |
| for (int h = minHisto + 1; h < maxHisto; h++) { |
| |
| |
| |
| if (std::abs(h - histo[h].belongingSegmentValue) > |
| std::abs(h - tmpBestNewSegVal)) |
| |
| histo[h].belongingSegmentValue = tmpBestNewSegVal; |
| } |
| } |
| |
| |
| |
| QVector<int> segValVec; |
| int tmpSegVal = -1; |
| int tmpSegId = -1; |
| for (int h = 255; h >= 0; h--) { |
| if (histo[h].belongingSegmentValue != tmpSegVal) { |
| segmentDepth_main.push_back((float)histo[h].belongingSegmentValue / |
| (float)UCHAR_MAX); |
| tmpSegVal = histo[h].belongingSegmentValue; |
| tmpSegId++; |
| segValVec.push_back(tmpSegVal); |
| } |
| histo[h].segmentId = tmpSegId; |
| } |
| |
| |
| for (int d = 0; d < segmentDepth_main.size() - 1; d++) |
| segmentDepth_sub.push_back( |
| (segmentDepth_main.at(d) + segmentDepth_main.at(d + 1)) / 2.0f); |
| |
| |
| tmpSegId = 0; |
| for (int seg = 0; seg < segValVec.size() - 1; seg++) { |
| int hMax = (seg == 0) ? 255 : segValVec.at(seg); |
| int hMin = (seg == segValVec.size() - 2) ? 0 : segValVec.at(seg + 1) + 1; |
| for (int h = hMax; h >= hMin; h--) histo[h].segmentId_sub = tmpSegId; |
| tmpSegId++; |
| } |
| |
| |
| depth_p = (unsigned char*)depth_buff; |
| unsigned char* main_p = (unsigned char*)indexMap_main; |
| unsigned char* sub_p = (unsigned char*)indexMap_sub; |
| |
| |
| float* ratio_p = (float*)mainSub_ratio; |
| for (int i = 0; i < size; i++, depth_p++, main_p++, sub_p++, ratio_p++) { |
| *main_p = (unsigned char)histo[(int)*depth_p].segmentId; |
| *sub_p = (unsigned char)histo[(int)*depth_p].segmentId_sub; |
| |
| float depth = (float)*depth_p / (float)UCHAR_MAX; |
| float main_segDepth = segmentDepth_main.at(*main_p); |
| float sub_segDepth = segmentDepth_sub.at(*sub_p); |
| |
| if (main_segDepth == sub_segDepth) |
| *ratio_p = 1.0f; |
| else { |
| *ratio_p = |
| 1.0f - (main_segDepth - depth) / (main_segDepth - sub_segDepth); |
| if (*ratio_p > 1.0f) *ratio_p = 1.0f; |
| if (*ratio_p < 0.0f) *ratio_p = 0.0f; |
| } |
| } |
| } |
| |
| |
| |
| |
| template <typename RASTER, typename PIXEL> |
| void Iwa_BokehRefFx::setOutputRaster(float4* srcMem, const RASTER dstRas, |
| TDimensionI dim, TDimensionI margin) { |
| int out_j = 0; |
| for (int j = margin.ly; j < dstRas->getLy() + margin.ly; j++, out_j++) { |
| PIXEL* pix = dstRas->pixels(out_j); |
| float4* chan_p = srcMem; |
| chan_p += j * dim.lx + margin.lx; |
| for (int i = 0; i < dstRas->getLx(); i++, pix++, chan_p++) { |
| float val; |
| val = (*chan_p).x * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->r = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| val = (*chan_p).y * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->g = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| val = (*chan_p).z * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->b = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| val = (*chan_p).w * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->m = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| } |
| } |
| } |
| |
| |
| |
| |
| inline float Iwa_BokehRefFx::calcIrisSize(const float depth, |
| const float bokehPixelAmount, |
| const double onFocusDistance) { |
| return ((float)onFocusDistance - depth) * bokehPixelAmount; |
| } |
| |
| |
| |
| |
| |
| |
| void Iwa_BokehRefFx::convertIris(const float irisSize, const TRectD& irisBBox, |
| const TTile& irisTile, |
| const TDimensionI& dimOut, |
| kiss_fft_cpx* fftcpx_iris_before) { |
| |
| TDimensionD irisOrgSize = irisBBox.getSize(); |
| |
| |
| double irisSizeResampleRatio = irisSize / irisOrgSize.lx; |
| |
| |
| TDimensionD resizedIrisSize(std::abs(irisSizeResampleRatio) * irisOrgSize.lx, |
| std::abs(irisSizeResampleRatio) * irisOrgSize.ly); |
| TDimensionI filterSize((int)std::ceil(resizedIrisSize.lx), |
| (int)std::ceil(resizedIrisSize.ly)); |
| TPointD resizeOffset((double)filterSize.lx - resizedIrisSize.lx, |
| (double)filterSize.ly - resizedIrisSize.ly); |
| |
| bool isIrisOffset[2] = {false, false}; |
| |
| if ((dimOut.lx - filterSize.lx) % 2 == 1) { |
| filterSize.lx++; |
| isIrisOffset[0] = true; |
| } |
| if ((dimOut.ly - filterSize.ly) % 2 == 1) { |
| filterSize.ly++; |
| isIrisOffset[1] = true; |
| } |
| |
| |
| if (filterSize.lx > dimOut.lx || filterSize.ly > dimOut.ly) { |
| std::cout |
| << "Error: The iris filter size becomes larger than the source size!" |
| << std::endl; |
| return; |
| } |
| |
| TRaster64P resizedIris(filterSize); |
| |
| |
| TAffine aff; |
| TPointD affOffset((isIrisOffset[0]) ? 0.5 : 1.0, |
| (isIrisOffset[1]) ? 0.5 : 1.0); |
| if (!isIrisOffset[0]) affOffset.x -= resizeOffset.x / 2; |
| if (!isIrisOffset[1]) affOffset.y -= resizeOffset.y / 2; |
| |
| aff = TTranslation(resizedIris->getCenterD() + affOffset); |
| aff *= TScale(irisSizeResampleRatio); |
| aff *= TTranslation(-(irisTile.getRaster()->getCenterD() + affOffset)); |
| |
| |
| TRop::resample(resizedIris, irisTile.getRaster(), aff); |
| |
| |
| float irisValAmount = 0.0; |
| |
| int iris_j = 0; |
| |
| for (int i = 0; i < dimOut.lx * dimOut.ly; i++) { |
| fftcpx_iris_before[i].r = 0.0; |
| fftcpx_iris_before[i].i = 0.0; |
| } |
| for (int j = (dimOut.ly - filterSize.ly) / 2; iris_j < filterSize.ly; |
| j++, iris_j++) { |
| TPixel64* pix = resizedIris->pixels(iris_j); |
| int iris_i = 0; |
| for (int i = (dimOut.lx - filterSize.lx) / 2; iris_i < filterSize.lx; |
| i++, iris_i++) { |
| |
| fftcpx_iris_before[j * dimOut.lx + i].r = |
| ((float)pix->r * 0.3f + (float)pix->g * 0.59f + |
| (float)pix->b * 0.11f) / |
| (float)USHRT_MAX; |
| irisValAmount += fftcpx_iris_before[j * dimOut.lx + i].r; |
| pix++; |
| } |
| } |
| |
| |
| for (int i = 0; i < dimOut.lx * dimOut.ly; i++) |
| fftcpx_iris_before[i].r /= irisValAmount; |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::convertRGBToExposure(const float4* source_buff, int size, |
| float filmGamma, |
| bool sourceIsPremultiplied) { |
| float4* source_p = (float4*)source_buff; |
| for (int i = 0; i < size; i++, source_p++) { |
| |
| if ((*source_p).w == 0.0f) { |
| (*source_p).x = 0.0f; |
| (*source_p).y = 0.0f; |
| (*source_p).z = 0.0f; |
| continue; |
| } |
| |
| |
| |
| |
| if (sourceIsPremultiplied) { |
| |
| (*source_p).x /= (*source_p).w; |
| (*source_p).y /= (*source_p).w; |
| (*source_p).z /= (*source_p).w; |
| } |
| |
| |
| (*source_p).x = pow(10, ((*source_p).x - 0.5f) / filmGamma); |
| (*source_p).y = pow(10, ((*source_p).y - 0.5f) / filmGamma); |
| (*source_p).z = pow(10, ((*source_p).z - 0.5f) / filmGamma); |
| |
| |
| (*source_p).x *= (*source_p).w; |
| (*source_p).y *= (*source_p).w; |
| (*source_p).z *= (*source_p).w; |
| } |
| } |
| |
| |
| |
| |
| |
| void Iwa_BokehRefFx::retrieveLayer(const float4* source_buff, |
| const float4* segment_layer_buff, |
| const unsigned char* indexMap_mainSub, |
| int index, int lx, int ly, bool fillGap, |
| bool doMedian, int margin) { |
| |
| |
| bool fill = (fillGap && !doMedian); |
| |
| float4* source_p = (float4*)source_buff; |
| float4* layer_p = (float4*)segment_layer_buff; |
| unsigned char* indexMap_p = (unsigned char*)indexMap_mainSub; |
| for (int i = 0; i < lx * ly; i++, source_p++, layer_p++, indexMap_p++) { |
| |
| |
| if ((int)(*indexMap_p) < index || (!fill && (int)(*indexMap_p) > index)) |
| continue; |
| |
| |
| (*layer_p).x = (*source_p).x; |
| (*layer_p).y = (*source_p).y; |
| (*layer_p).z = (*source_p).z; |
| (*layer_p).w = (*source_p).w; |
| } |
| |
| if (!fillGap || !doMedian) return; |
| if (margin == 0) return; |
| |
| |
| unsigned char* generation_buff; |
| TRasterGR8P generation_buff_ras = allocateRasterAndLock<unsigned char>( |
| &generation_buff, TDimensionI(lx, ly)); |
| |
| for (int gen = 0; gen < margin; gen++) { |
| |
| doSingleMedian(source_buff, segment_layer_buff, indexMap_mainSub, index, lx, |
| ly, generation_buff, gen + 1); |
| } |
| |
| generation_buff_ras->unlock(); |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::doSingleMedian(const float4* source_buff, |
| const float4* segment_layer_buff, |
| const unsigned char* indexMap_mainSub, |
| int index, int lx, int ly, |
| const unsigned char* generation_buff, |
| int curGen) { |
| float4* source_p = (float4*)source_buff; |
| float4* layer_p = (float4*)segment_layer_buff; |
| unsigned char* indexMap_p = (unsigned char*)indexMap_mainSub; |
| unsigned char* gen_p = (unsigned char*)generation_buff; |
| for (int posY = 0; posY < ly; posY++) { |
| for (int posX = 0; posX < lx; |
| posX++, source_p++, layer_p++, indexMap_p++, gen_p++) { |
| |
| if ((int)(*indexMap_p) <= index) continue; |
| |
| if ((*gen_p) > 0) continue; |
| |
| |
| float4 neighbor[8]; |
| int neighbor_amount = 0; |
| for (int ky = posY - 1; ky <= posY + 1; ky++) { |
| for (int kx = posX - 1; kx <= posX + 1; kx++) { |
| |
| if (kx == posX && ky == posY) continue; |
| |
| if (ky < 0 || ky >= ly || kx < 0 || kx >= lx) continue; |
| |
| int neighborId = ky * lx + kx; |
| |
| if ((int)indexMap_mainSub[neighborId] != |
| index && |
| |
| (generation_buff[neighborId] == 0 || |
| |
| |
| generation_buff[neighborId] == curGen)) |
| |
| |
| |
| |
| continue; |
| |
| |
| float brightness = source_buff[neighborId].x * 0.3f + |
| source_buff[neighborId].y * 0.59f + |
| source_buff[neighborId].z * 0.11f; |
| |
| int ins_index; |
| for (ins_index = 0; ins_index < neighbor_amount; ins_index++) { |
| if (neighbor[ins_index].w < brightness) break; |
| } |
| |
| for (int k = neighbor_amount - 1; k >= ins_index; k--) { |
| neighbor[k + 1].x = neighbor[k].x; |
| neighbor[k + 1].y = neighbor[k].y; |
| neighbor[k + 1].z = neighbor[k].z; |
| neighbor[k + 1].w = neighbor[k].w; |
| } |
| |
| neighbor[ins_index].x = source_buff[neighborId].x; |
| neighbor[ins_index].y = source_buff[neighborId].y; |
| neighbor[ins_index].z = source_buff[neighborId].z; |
| neighbor[ins_index].w = brightness; |
| |
| |
| neighbor_amount++; |
| } |
| } |
| |
| |
| if (neighbor_amount == 0) continue; |
| |
| |
| bool flag = ((posX + posY) % 2 == 0); |
| |
| int pickIndex = (flag) |
| ? (int)std::floor((float)(neighbor_amount - 1) / 2.0f) |
| : (int)std::ceil((float)(neighbor_amount - 1) / 2.0f); |
| |
| |
| (*layer_p).x = neighbor[pickIndex].x; |
| (*layer_p).y = neighbor[pickIndex].y; |
| (*layer_p).z = neighbor[pickIndex].z; |
| (*layer_p).w = (*source_p).w; |
| |
| |
| (*gen_p) = (unsigned char)curGen; |
| } |
| } |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::compositeAsIs(const float4* segment_layer_buff, |
| const float4* result_buff_mainSub, |
| int size) { |
| float4* layer_p = (float4*)segment_layer_buff; |
| float4* result_p = (float4*)result_buff_mainSub; |
| for (int i = 0; i < size; i++, layer_p++, result_p++) { |
| |
| if ((*layer_p).w == 1.0f) { |
| (*result_p).x = (*layer_p).x; |
| (*result_p).y = (*layer_p).y; |
| (*result_p).z = (*layer_p).z; |
| (*result_p).w = 1.0f; |
| continue; |
| } |
| |
| else if ((*layer_p).w == 0.0f) |
| continue; |
| |
| else { |
| (*result_p).x = (*layer_p).x + (*result_p).x * (1.0f - (*layer_p).w); |
| (*result_p).y = (*layer_p).y + (*result_p).y * (1.0f - (*layer_p).w); |
| (*result_p).z = (*layer_p).z + (*result_p).z * (1.0f - (*layer_p).w); |
| (*result_p).w = (*layer_p).w + (*result_p).w * (1.0f - (*layer_p).w); |
| } |
| } |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::retrieveChannel(const float4* segment_layer_buff, |
| kiss_fft_cpx* fftcpx_r_before, |
| kiss_fft_cpx* fftcpx_g_before, |
| kiss_fft_cpx* fftcpx_b_before, |
| kiss_fft_cpx* fftcpx_a_before, |
| int size) { |
| float4* layer_p = (float4*)segment_layer_buff; |
| for (int i = 0; i < size; i++, layer_p++) { |
| fftcpx_r_before[i].r = (*layer_p).x; |
| fftcpx_g_before[i].r = (*layer_p).y; |
| fftcpx_b_before[i].r = (*layer_p).z; |
| fftcpx_a_before[i].r = (*layer_p).w; |
| } |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::multiplyFilter(kiss_fft_cpx* fftcpx_channel, |
| kiss_fft_cpx* fftcpx_iris, |
| int size) { |
| for (int i = 0; i < size; i++) { |
| float re, im; |
| re = fftcpx_channel[i].r * fftcpx_iris[i].r - |
| fftcpx_channel[i].i * fftcpx_iris[i].i; |
| im = fftcpx_channel[i].r * fftcpx_iris[i].i + |
| fftcpx_channel[i].i * fftcpx_iris[i].r; |
| |
| fftcpx_channel[i].r = re; |
| fftcpx_channel[i].i = im; |
| } |
| } |
| |
| |
| |
| |
| void Iwa_BokehRefFx::compositeAlpha(const float4* result_buff, |
| const kiss_fft_cpx* fftcpx_alpha, |
| int lx, int ly) { |
| int size = lx * ly; |
| float4* result_p = (float4*)result_buff; |
| for (int i = 0; i < size; i++, result_p++) { |
| |
| float alpha = fftcpx_alpha[getCoord(i, lx, ly)].r / (float)size; |
| |
| if ((*result_p).w < 1.0f) { |
| if (alpha >= 1.0f) |
| (*result_p).w = 1.0f; |
| else |
| (*result_p).w = alpha + ((*result_p).w * (1.0f - alpha)); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| void Iwa_BokehRefFx::interpolateExposureAndConvertToRGB( |
| const float4* result_main_buff, |
| const float4* result_sub_buff, |
| const float* mainSub_ratio, |
| float filmGamma, |
| const float4* source_buff, |
| int size) { |
| float4* resultMain_p = (float4*)result_main_buff; |
| float4* resultSub_p = (float4*)result_sub_buff; |
| float* ratio_p = (float*)mainSub_ratio; |
| float4* out_p = (float4*)source_buff; |
| for (int i = 0; i < size; |
| i++, resultMain_p++, resultSub_p++, ratio_p++, out_p++) { |
| |
| float4 result; |
| |
| result.x = |
| (*resultMain_p).x * (*ratio_p) + (*resultSub_p).x * (1.0f - (*ratio_p)); |
| result.y = |
| (*resultMain_p).y * (*ratio_p) + (*resultSub_p).y * (1.0f - (*ratio_p)); |
| result.z = |
| (*resultMain_p).z * (*ratio_p) + (*resultSub_p).z * (1.0f - (*ratio_p)); |
| result.w = |
| (*resultMain_p).w * (*ratio_p) + (*resultSub_p).w * (1.0f - (*ratio_p)); |
| |
| (*out_p).w = result.w; |
| |
| |
| |
| |
| if (result.w == 0.0f) { |
| (*out_p).x = 0.0f; |
| (*out_p).y = 0.0f; |
| (*out_p).z = 0.0f; |
| continue; |
| } |
| |
| |
| result.x = log10(result.x) * filmGamma + 0.5f; |
| result.y = log10(result.y) * filmGamma + 0.5f; |
| result.z = log10(result.z) * filmGamma + 0.5f; |
| |
| (*out_p).x = |
| (result.x > 1.0f) ? 1.0f : ((result.x < 0.0f) ? 0.0f : result.x); |
| (*out_p).y = |
| (result.y > 1.0f) ? 1.0f : ((result.y < 0.0f) ? 0.0f : result.y); |
| (*out_p).z = |
| (result.z > 1.0f) ? 1.0f : ((result.z < 0.0f) ? 0.0f : result.z); |
| } |
| } |
| |
| |
| |
| Iwa_BokehRefFx::Iwa_BokehRefFx() |
| : m_onFocusDistance(0.5) |
| , m_bokehAmount(30.0) |
| , m_hardness(0.3) |
| , m_distancePrecision(10) |
| , m_fillGap(true) |
| , m_doMedian(true) { |
| |
| addInputPort("Iris", m_iris); |
| addInputPort("Source", m_source); |
| addInputPort("Depth", m_depth); |
| |
| bindParam(this, "on_focus_distance", m_onFocusDistance, false); |
| bindParam(this, "bokeh_amount", m_bokehAmount, false); |
| bindParam(this, "hardness", m_hardness, false); |
| bindParam(this, "distance_precision", m_distancePrecision, false); |
| bindParam(this, "fill_gap", m_fillGap, false); |
| bindParam(this, "fill_gap_with_median_filter", m_doMedian, false); |
| |
| |
| m_onFocusDistance->setValueRange(0, 1); |
| m_bokehAmount->setValueRange(0, 300); |
| m_bokehAmount->setMeasureName("fxLength"); |
| m_hardness->setValueRange(0.05, 20.0); |
| m_distancePrecision->setValueRange(3, 128); |
| } |
| |
| |
| |
| void Iwa_BokehRefFx::doCompute(TTile& tile, double frame, |
| const TRenderSettings& settings) { |
| |
| if (!m_iris.isConnected() || !m_source.isConnected() || |
| !m_depth.isConnected()) { |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| QList<TRasterGR8P> rasterList; |
| |
| |
| float bokehPixelAmount = getBokehPixelAmount(frame, settings.m_affine); |
| |
| |
| |
| double onFocusDistance = m_onFocusDistance->getValue(frame); |
| float maxIrisSize = |
| bokehPixelAmount * std::max((1.0 - onFocusDistance), onFocusDistance); |
| |
| int margin = |
| (maxIrisSize > 1.0f) ? (int)(std::ceil((maxIrisSize - 1.0f) / 2.0f)) : 0; |
| |
| |
| TRectD rectOut(tile.m_pos, TDimensionD(tile.getRaster()->getLx(), |
| tile.getRaster()->getLy())); |
| rectOut = rectOut.enlarge(static_cast<double>(margin)); |
| |
| TDimensionI dimOut(static_cast<int>(rectOut.getLx() + 0.5), |
| static_cast<int>(rectOut.getLy() + 0.5)); |
| |
| |
| |
| if (dimOut.lx < 10000 && dimOut.ly < 10000) { |
| int new_x = kiss_fft_next_fast_size(dimOut.lx); |
| int new_y = kiss_fft_next_fast_size(dimOut.ly); |
| |
| rectOut = rectOut.enlarge(static_cast<double>(new_x - dimOut.lx) / 2.0, |
| static_cast<double>(new_y - dimOut.ly) / 2.0); |
| |
| dimOut.lx = new_x; |
| dimOut.ly = new_y; |
| } |
| |
| |
| |
| |
| bool isPremultiplied; |
| |
| |
| float4* source_buff; |
| rasterList.append(allocateRasterAndLock<float4>(&source_buff, dimOut)); |
| |
| { |
| |
| |
| TTile sourceTile; |
| m_source->allocateAndCompute(sourceTile, rectOut.getP00(), dimOut, |
| tile.getRaster(), frame, settings); |
| |
| TRaster32P ras32 = (TRaster32P)sourceTile.getRaster(); |
| TRaster64P ras64 = (TRaster64P)sourceTile.getRaster(); |
| lock.lockForRead(); |
| if (ras32) |
| isPremultiplied = |
| setSourceRaster<TRaster32P, TPixel32>(ras32, source_buff, dimOut); |
| else if (ras64) |
| isPremultiplied = |
| setSourceRaster<TRaster64P, TPixel64>(ras64, source_buff, dimOut); |
| lock.unlock(); |
| } |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| |
| |
| |
| unsigned char* indexMap_main; |
| unsigned char* indexMap_sub; |
| rasterList.append( |
| allocateRasterAndLock<unsigned char>(&indexMap_main, dimOut)); |
| rasterList.append( |
| allocateRasterAndLock<unsigned char>(&indexMap_sub, dimOut)); |
| |
| |
| float* mainSub_ratio; |
| rasterList.append(allocateRasterAndLock<float>(&mainSub_ratio, dimOut)); |
| |
| |
| QVector<float> segmentDepth_main; |
| QVector<float> segmentDepth_sub; |
| { |
| |
| unsigned char* depth_buff; |
| TRasterGR8P depth_buff_ras = |
| allocateRasterAndLock<unsigned char>(&depth_buff, dimOut); |
| { |
| TTile depthTile; |
| m_depth->allocateAndCompute(depthTile, rectOut.getP00(), dimOut, |
| tile.getRaster(), frame, settings); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| depth_buff_ras->unlock(); |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| |
| |
| TRasterGR8P rasGR8 = (TRasterGR8P)depthTile.getRaster(); |
| TRasterGR16P rasGR16 = (TRasterGR16P)depthTile.getRaster(); |
| TRaster32P ras32 = (TRaster32P)depthTile.getRaster(); |
| TRaster64P ras64 = (TRaster64P)depthTile.getRaster(); |
| lock.lockForRead(); |
| if (rasGR8) |
| setDepthRasterGray<TRasterGR8P, TPixelGR8>(rasGR8, depth_buff, dimOut); |
| else if (rasGR16) |
| setDepthRasterGray<TRasterGR16P, TPixelGR16>(rasGR16, depth_buff, |
| dimOut); |
| else if (ras32) |
| setDepthRaster<TRaster32P, TPixel32>(ras32, depth_buff, dimOut); |
| else if (ras64) |
| setDepthRaster<TRaster64P, TPixel64>(ras64, depth_buff, dimOut); |
| lock.unlock(); |
| } |
| |
| defineSegemntDepth(indexMap_main, indexMap_sub, mainSub_ratio, depth_buff, |
| dimOut, frame, segmentDepth_main, segmentDepth_sub); |
| |
| depth_buff_ras->unlock(); |
| } |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| |
| |
| TRectD irisBBox; |
| m_iris->getBBox(frame, irisBBox, settings); |
| |
| TTile irisTile; |
| m_iris->allocateAndCompute( |
| irisTile, irisBBox.getP00(), |
| TDimension(static_cast<int>(irisBBox.getLx() + 0.5), |
| static_cast<int>(irisBBox.getLy() + 0.5)), |
| tile.getRaster(), frame, settings); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| |
| |
| doCompute_CPU(frame, settings, bokehPixelAmount, maxIrisSize, margin, dimOut, |
| source_buff, indexMap_main, indexMap_sub, mainSub_ratio, |
| segmentDepth_main, segmentDepth_sub, irisTile, irisBBox, |
| isPremultiplied); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| TDimensionI actualMargin((dimOut.lx - tile.getRaster()->getSize().lx) / 2, |
| (dimOut.ly - tile.getRaster()->getSize().ly) / 2); |
| |
| tile.getRaster()->clear(); |
| TRaster32P outRas32 = (TRaster32P)tile.getRaster(); |
| TRaster64P outRas64 = (TRaster64P)tile.getRaster(); |
| lock.lockForWrite(); |
| if (outRas32) |
| setOutputRaster<TRaster32P, TPixel32>(source_buff, outRas32, dimOut, |
| actualMargin); |
| else if (outRas64) |
| setOutputRaster<TRaster64P, TPixel64>(source_buff, outRas64, dimOut, |
| actualMargin); |
| lock.unlock(); |
| |
| |
| releaseAllRasters(rasterList); |
| } |
| |
| |
| |
| void Iwa_BokehRefFx::doCompute_CPU( |
| const double frame, const TRenderSettings& settings, float bokehPixelAmount, |
| float maxIrisSize, int margin, TDimensionI& dimOut, float4* source_buff, |
| unsigned char* indexMap_main, unsigned char* indexMap_sub, |
| float* mainSub_ratio, QVector<float>& segmentDepth_main, |
| QVector<float>& segmentDepth_sub, TTile& irisTile, TRectD& irisBBox, |
| bool sourceIsPremultiplied) { |
| QList<TRasterGR8P> rasterList; |
| QList<kiss_fftnd_cfg> planList; |
| |
| |
| |
| |
| QMutexLocker fx_locker(&fx_mutex); |
| |
| |
| |
| |
| kiss_fft_cpx* fftcpx_iris_before; |
| kiss_fft_cpx* fftcpx_iris; |
| rasterList.append( |
| allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_iris_before, dimOut)); |
| rasterList.append(allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_iris, dimOut)); |
| |
| |
| float4* segment_layer_buff; |
| rasterList.append(allocateRasterAndLock<float4>(&segment_layer_buff, dimOut)); |
| |
| |
| kiss_fft_cpx* fftcpx_alpha_before; |
| kiss_fft_cpx* fftcpx_alpha; |
| rasterList.append( |
| allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_alpha_before, dimOut)); |
| rasterList.append(allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_alpha, dimOut)); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| return; |
| } |
| |
| |
| kiss_fft_cpx* fftcpx_r_before; |
| kiss_fft_cpx* fftcpx_g_before; |
| kiss_fft_cpx* fftcpx_b_before; |
| kiss_fft_cpx* fftcpx_r; |
| kiss_fft_cpx* fftcpx_g; |
| kiss_fft_cpx* fftcpx_b; |
| rasterList.append( |
| allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_r_before, dimOut)); |
| rasterList.append( |
| allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_g_before, dimOut)); |
| rasterList.append( |
| allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_b_before, dimOut)); |
| rasterList.append(allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_r, dimOut)); |
| rasterList.append(allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_g, dimOut)); |
| rasterList.append(allocateRasterAndLock<kiss_fft_cpx>(&fftcpx_b, dimOut)); |
| |
| |
| float4* result_main_buff; |
| float4* result_sub_buff; |
| rasterList.append(allocateRasterAndLock<float4>(&result_main_buff, dimOut)); |
| rasterList.append(allocateRasterAndLock<float4>(&result_sub_buff, dimOut)); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRasters(rasterList); |
| return; |
| } |
| |
| |
| int dims[2] = {dimOut.ly, dimOut.lx}; |
| kiss_fftnd_cfg kissfft_plan_fwd = kiss_fftnd_alloc(dims, 2, false, 0, 0); |
| kiss_fftnd_cfg kissfft_plan_bkwd = kiss_fftnd_alloc(dims, 2, true, 0, 0); |
| planList.append(kissfft_plan_fwd); |
| planList.append(kissfft_plan_bkwd); |
| |
| kiss_fftnd_cfg kissfft_plan_r_fwd = kiss_fftnd_alloc(dims, 2, false, 0, 0); |
| kiss_fftnd_cfg kissfft_plan_r_bkwd = kiss_fftnd_alloc(dims, 2, true, 0, 0); |
| kiss_fftnd_cfg kissfft_plan_g_fwd = kiss_fftnd_alloc(dims, 2, false, 0, 0); |
| kiss_fftnd_cfg kissfft_plan_g_bkwd = kiss_fftnd_alloc(dims, 2, true, 0, 0); |
| kiss_fftnd_cfg kissfft_plan_b_fwd = kiss_fftnd_alloc(dims, 2, false, 0, 0); |
| kiss_fftnd_cfg kissfft_plan_b_bkwd = kiss_fftnd_alloc(dims, 2, true, 0, 0); |
| planList.append(kissfft_plan_r_fwd); |
| planList.append(kissfft_plan_r_bkwd); |
| planList.append(kissfft_plan_g_fwd); |
| planList.append(kissfft_plan_g_bkwd); |
| planList.append(kissfft_plan_b_fwd); |
| planList.append(kissfft_plan_b_bkwd); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| int size = dimOut.lx * dimOut.ly; |
| |
| |
| memset(result_main_buff, 0, sizeof(float4) * size); |
| memset(result_sub_buff, 0, sizeof(float4) * size); |
| |
| |
| float filmGamma = (float)m_hardness->getValue(frame); |
| bool fillGap = m_fillGap->getValue(); |
| bool doMedian = m_doMedian->getValue(); |
| |
| |
| convertRGBToExposure(source_buff, size, filmGamma, sourceIsPremultiplied); |
| |
| |
| for (int mainSub = 0; mainSub < 2; mainSub++) { |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| float4* result_buff_mainSub; |
| QVector<float> segmentDepth_mainSub; |
| unsigned char* indexMap_mainSub; |
| if (mainSub == 0) |
| { |
| result_buff_mainSub = result_main_buff; |
| segmentDepth_mainSub = segmentDepth_main; |
| indexMap_mainSub = indexMap_main; |
| } else |
| { |
| result_buff_mainSub = result_sub_buff; |
| segmentDepth_mainSub = segmentDepth_sub; |
| indexMap_mainSub = indexMap_sub; |
| } |
| |
| |
| for (int index = 0; index < segmentDepth_mainSub.size(); index++) { |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| float irisSize = |
| calcIrisSize(segmentDepth_mainSub.at(index), bokehPixelAmount, |
| m_onFocusDistance->getValue(frame)); |
| |
| |
| memset(segment_layer_buff, 0, sizeof(float4) * size); |
| |
| |
| retrieveLayer(source_buff, segment_layer_buff, indexMap_mainSub, index, |
| dimOut.lx, dimOut.ly, fillGap, doMedian, |
| (index == segmentDepth_mainSub.size() - 1) ? 0 : margin); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| if (-1.0 <= irisSize && 1.0 >= irisSize) { |
| |
| compositeAsIs(segment_layer_buff, result_buff_mainSub, size); |
| |
| continue; |
| } |
| |
| |
| |
| |
| |
| |
| convertIris(irisSize, irisBBox, irisTile, dimOut, fftcpx_iris_before); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| kiss_fftnd(kissfft_plan_fwd, fftcpx_iris_before, fftcpx_iris); |
| |
| |
| |
| memset(fftcpx_alpha_before, 0, sizeof(kiss_fft_cpx) * size); |
| |
| memset(fftcpx_r_before, 0, sizeof(kiss_fft_cpx) * size); |
| memset(fftcpx_g_before, 0, sizeof(kiss_fft_cpx) * size); |
| memset(fftcpx_b_before, 0, sizeof(kiss_fft_cpx) * size); |
| |
| |
| retrieveChannel(segment_layer_buff, |
| fftcpx_r_before, |
| fftcpx_g_before, |
| fftcpx_b_before, |
| fftcpx_alpha_before, |
| size); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| kiss_fftnd(kissfft_plan_fwd, fftcpx_alpha_before, fftcpx_alpha); |
| |
| |
| |
| multiplyFilter(fftcpx_alpha, |
| fftcpx_iris, |
| size); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| |
| kiss_fftnd(kissfft_plan_bkwd, fftcpx_alpha, fftcpx_alpha_before); |
| |
| |
| |
| compositeAlpha(result_buff_mainSub, |
| fftcpx_alpha_before, |
| dimOut.lx, dimOut.ly); |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| BokehRefThread threadR(0, fftcpx_r_before, fftcpx_r, fftcpx_alpha_before, |
| fftcpx_iris, result_buff_mainSub, |
| kissfft_plan_r_fwd, kissfft_plan_r_bkwd, dimOut); |
| BokehRefThread threadG(1, fftcpx_g_before, fftcpx_g, fftcpx_alpha_before, |
| fftcpx_iris, result_buff_mainSub, |
| kissfft_plan_g_fwd, kissfft_plan_g_bkwd, dimOut); |
| BokehRefThread threadB(2, fftcpx_b_before, fftcpx_b, fftcpx_alpha_before, |
| fftcpx_iris, result_buff_mainSub, |
| kissfft_plan_b_fwd, kissfft_plan_b_bkwd, dimOut); |
| |
| |
| |
| |
| |
| |
| |
| |
| bool renderInSingleThread = false; |
| |
| if (renderInSingleThread) { |
| threadR.run(); |
| threadG.run(); |
| threadB.run(); |
| } else { |
| threadR.start(); |
| threadG.start(); |
| threadB.start(); |
| int waitCount = 0; |
| while (1) { |
| if ((settings.m_isCanceled && *settings.m_isCanceled) || |
| waitCount >= 2000) |
| { |
| if (!threadR.isFinished()) threadR.terminateThread(); |
| if (!threadG.isFinished()) threadG.terminateThread(); |
| if (!threadB.isFinished()) threadB.terminateThread(); |
| while (!threadR.isFinished() || !threadG.isFinished() || |
| !threadB.isFinished()) { |
| } |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| if (threadR.isFinished() && threadG.isFinished() && |
| threadB.isFinished()) |
| break; |
| QThread::msleep(50); |
| waitCount++; |
| } |
| } |
| |
| } |
| } |
| |
| |
| if (settings.m_isCanceled && *settings.m_isCanceled) { |
| releaseAllRastersAndPlans(rasterList, planList); |
| return; |
| } |
| |
| |
| |
| |
| interpolateExposureAndConvertToRGB(result_main_buff, |
| result_sub_buff, |
| mainSub_ratio, |
| filmGamma, |
| source_buff, |
| size); |
| |
| |
| releaseAllRastersAndPlans(rasterList, planList); |
| } |
| |
| |
| |
| bool Iwa_BokehRefFx::doGetBBox(double frame, TRectD& bBox, |
| const TRenderSettings& info) { |
| bBox = TConsts::infiniteRectD; |
| return true; |
| } |
| |
| |
| |
| bool Iwa_BokehRefFx::canHandle(const TRenderSettings& info, double frame) { |
| return false; |
| } |
| |
| FX_PLUGIN_IDENTIFIER(Iwa_BokehRefFx, "iwa_BokehRefFx") |