diff --git a/OverLua/docs/overlua.txt b/OverLua/docs/overlua.txt index db093eef6..e36b58656 100644 --- a/OverLua/docs/overlua.txt +++ b/OverLua/docs/overlua.txt @@ -157,6 +157,11 @@ Apply a variable strength directional gaussian kernel blur to the image. Also known as motion blur. The angle is given in radians. +raster.radial_blur(surface, cx, cy, sigma) + +Apply a variable strength radial gaussian blur centered on pixel (cx,cy). + + raster.invert(surface) Invert the colour in the given surface. diff --git a/OverLua/docs/test2.lua b/OverLua/docs/test2.lua index cf7406efb..a39dc4407 100644 --- a/OverLua/docs/test2.lua +++ b/OverLua/docs/test2.lua @@ -36,7 +36,7 @@ function render_frame(f, t) ctx.text_path("OverLua") ctx.fill() - raster.gaussian_blur(surf, (1-math.cos(t*10))*2) + raster.directional_blur(surf, t, 5) f.overlay_cairo_surface(surf, 200, 50) end diff --git a/OverLua/docs/test3.lua b/OverLua/docs/test3.lua index 8dc450f82..d36089865 100644 --- a/OverLua/docs/test3.lua +++ b/OverLua/docs/test3.lua @@ -3,6 +3,7 @@ function render_frame(f, t) --raster.gaussian_blur(surf, t)--1+(1-math.cos(t*10))*2) --raster.invert(surf) --raster.separable_filter(surf, {-1, 3, -1}, 1) - raster.directional_blur(surf, t, t/10) + --raster.directional_blur(surf, t, t/10) + raster.radial_blur(surf, 200, 200, t/60) f.overlay_cairo_surface(surf, 0, 0) end diff --git a/OverLua/raster_ops.cpp b/OverLua/raster_ops.cpp index c2e883205..91bced849 100644 --- a/OverLua/raster_ops.cpp +++ b/OverLua/raster_ops.cpp @@ -477,7 +477,8 @@ struct DirectionalBlurFilter { res.G() = g; res.B() = b; return res; - }}; + } +}; static int directional_blur(lua_State *L) @@ -493,6 +494,99 @@ static int directional_blur(lua_State *L) } +struct RadialBlurFilter { + GaussianKernel gk; + int cx, cy; + RadialBlurFilter(int x, int y, double sigma) : + gk(sigma), cx(x), cy(y) + { + } + inline PixelFormat::A8 a8(BaseImage &src, int x, int y) + { + if (x == cx && y == cy) return src.Pixel(x, y); + double xstep = x-cx, ystep = y-cy, ivlen = 1/sqrt(xstep*xstep+ystep*ystep); + xstep *= ivlen; ystep *= ivlen; + int divisor = 0; + int a = 0; + for (int t = 0, i = gk.width/2; i < gk.width; t++, i++) { + //PixelFormat::A8 &srcpx = GetPixelBilinear(src, x+xstep*t, y+ystep*t); + PixelFormat::A8 &srcpx = EdgeCondition::repeat(src, (int)(x+xstep*t), (int)(y+ystep*t)); + a += srcpx.A() * gk.kernel[i]; + divisor += gk.kernel[i]; + } + PixelFormat::A8 res; + a = a / divisor; if (a < 0) a = 0; if (a > 255) a = 255; + res.A() = a; + return res; + } + inline PixelFormat::cairo_rgb24 rgb24(BaseImage &src, int x, int y) + { + if (x == cx && y == cy) return src.Pixel(x, y); + double xstep = x-cx, ystep = y-cy, ivlen = 1/sqrt(xstep*xstep+ystep*ystep); + xstep *= ivlen; ystep *= ivlen; + int divisor = 0; + int r = 0, g = 0, b = 0; + for (int t = 0, i = gk.width/2; i < gk.width; t++, i++) { + //PixelFormat::A8 &srcpx = GetPixelBilinear(src, x+xstep*t, y+ystep*t); + PixelFormat::cairo_rgb24 &srcpx = EdgeCondition::repeat(src, (int)(x+xstep*t), (int)(y+ystep*t)); + r += srcpx.R() * gk.kernel[i]; + g += srcpx.G() * gk.kernel[i]; + b += srcpx.B() * gk.kernel[i]; + divisor += gk.kernel[i]; + } + PixelFormat::cairo_rgb24 res; + r = r / divisor; if (r < 0) r = 0; if (r > 255) r = 255; + g = g / divisor; if (g < 0) g = 0; if (g > 255) g = 255; + b = b / divisor; if (b < 0) b = 0; if (b > 255) b = 255; + res.R() = r; + res.G() = g; + res.B() = b; + return res; + } + inline PixelFormat::cairo_argb32 argb32(BaseImage &src, int x, int y) + { + if (x == cx && y == cy) return src.Pixel(x, y); + double xstep = x-cx, ystep = y-cy, ivlen = 1/sqrt(xstep*xstep+ystep*ystep); + xstep *= ivlen; ystep *= ivlen; + int divisor = 0; + int a = 0, r = 0, g = 0, b = 0; + for (int t = 0, i = gk.width/2; i < gk.width; t++, i++) { + //PixelFormat::A8 &srcpx = GetPixelBilinear(src, x+xstep*t, y+ystep*t); + PixelFormat::cairo_argb32 &srcpx = EdgeCondition::repeat(src, (int)(x+xstep*t), (int)(y+ystep*t)); + a += srcpx.A() * gk.kernel[i]; + r += srcpx.R() * gk.kernel[i]; + g += srcpx.G() * gk.kernel[i]; + b += srcpx.B() * gk.kernel[i]; + divisor += gk.kernel[i]; + } + PixelFormat::cairo_argb32 res; + a = a / divisor; if (a < 0) a = 0; if (a > 255) a = 255; + r = r / divisor; if (r < 0) r = 0; if (r > 255) r = 255; + g = g / divisor; if (g < 0) g = 0; if (g > 255) g = 255; + b = b / divisor; if (b < 0) b = 0; if (b > 255) b = 255; + res.A() = a; + res.R() = r; + res.G() = g; + res.B() = b; + return res; + } +}; + + +static int radial_blur(lua_State *L) +{ + cairo_surface_t *surf = CheckSurface(L, 1); + int x = luaL_checkint(L, 2); + int y = luaL_checkint(L, 3); + double sigma = luaL_checknumber(L, 4); + + RadialBlurFilter filter(x, y, sigma); + ApplyGeneralFilter(L, surf, filter); + + return 0; +} + + static int invert_image(lua_State *L) { cairo_surface_t *surf = CheckSurface(L, 1); @@ -595,7 +689,8 @@ static int separable_filter(lua_State *L) // Registration static luaL_Reg rasterlib[] = { - {"gaussian_blur", gaussian_blur}, {"box_blur", box_blur}, {"directional_blur", directional_blur}, + {"gaussian_blur", gaussian_blur}, {"box_blur", box_blur}, + {"directional_blur", directional_blur}, {"radial_blur", radial_blur}, {"separable_filter", separable_filter}, {"invert", invert_image}, {NULL, NULL}