/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "picture/pict.h" #include "color/color.h" #include "log/log.h" using namespace GS; //------------------------------------------------------------------------------ bool Picture::ApplyConvolution(uint k_width, uint k_height, const int *p_w, int weight, int pass, const Rect *clip_rect) { if (GetBpp() != 32) __ERR__(__LOG_E__ << "Convolution filter only supported on 32bpp picture.\n", false); if (!k_width || !k_height) __ERR__(__LOG_E__ << "Invalid kernel size (" << k_width << "x" << k_height << ").\n", false); if (pass <= 0) return true; // Clipping rect. Rect rect = GetRect(); if (!clip_rect) clip_rect = ▭ // Setup flip chain. Picture tmp(*this), *src, *dst; if (pass & 1) { src = &tmp; dst = this; } else { src = this; dst = &tmp; } // Perform convolution. for (int p = 0; p < pass; ++p) { uchar *pdata = dst->GetDataOffset(clip_rect->sx, clip_rect->sy); for (int y = 0; y < clip_rect->GetHeight(); ++y) { uchar *pscan = pdata; for (int x = 0; x < rect.GetWidth(); ++x) { int sx = x - k_width / 2, sy = y - k_height / 2; int k_sx = Types::Max (sx, clip_rect->sx), k_sy = Types::Max (sy, clip_rect->sy); int k_ex = Types::Min (k_width + x - k_width / 2, clip_rect->ex), k_ey = Types::Min (k_height + y - k_height / 2, clip_rect->ey); const int *w = p_w + Types::Max(0, clip_rect->sx - sx) + Types::Max(0, clip_rect->sy - sy) * k_width; int k = 0; int accu[4] = { 0, 0, 0, 0 }; for (int ky = k_sy; ky < k_ey; ++ky) { const int *sw = w; for (int kx = k_sx; kx < k_ex; ++kx) { uchar *psrc = src->GetDataOffset(kx, ky); accu[0] += psrc[0] * *sw; accu[1] += psrc[1] * *sw; accu[2] += psrc[2] * *sw; accu[3] += psrc[3] * *sw; k += *sw++; } w += k_width; } k = k ? (weight << 6) / k : (weight << 6); pscan[0] = (uchar)Types::Clamp((accu[0] * k) >> 14, 0, 255); pscan[1] = (uchar)Types::Clamp((accu[1] * k) >> 14, 0, 255); pscan[2] = (uchar)Types::Clamp((accu[2] * k) >> 14, 0, 255); pscan[3] = (uchar)Types::Clamp((accu[3] * k) >> 14, 0, 255); pscan += 4; } pdata += dst->GetPitch(); } Picture *swp = dst; dst = src; src = swp; } return true; } //------------------------------------------------------------------------------