95 lines
2.6 KiB
C++
95 lines
2.6 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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 <int> *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 <int> 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 <int> (sx, clip_rect->sx),
|
|
k_sy = Types::Max <int> (sy, clip_rect->sy);
|
|
int k_ex = Types::Min <int> (k_width + x - k_width / 2, clip_rect->ex),
|
|
k_ey = Types::Min <int> (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;
|
|
}
|
|
//------------------------------------------------------------------------------
|