diff --git a/OverLua/docs/expression-evaluator.txt b/OverLua/docs/expression-evaluator.txt index 2cb3ad7eb..1036aaf50 100644 --- a/OverLua/docs/expression-evaluator.txt +++ b/OverLua/docs/expression-evaluator.txt @@ -217,4 +217,10 @@ else return the third argument. Sample programs --------------- -To be written. No functions in OverLua use the expression evaluator yet. +For raster.pixel_value_map: + +"rand =t0 t0 =R t0 =G t0 =B" +Create a field of random gray-values. + +"0 =R 1 G - =G" +Zero out the red channel and invert the green channel. diff --git a/OverLua/docs/overlua.txt b/OverLua/docs/overlua.txt index e36b58656..d3492043c 100644 --- a/OverLua/docs/overlua.txt +++ b/OverLua/docs/overlua.txt @@ -188,6 +188,25 @@ The filter is one-dimensional, but is applied first horizontally and then vertically ovre the image to get the final image. +raster.pixel_value_map(surface, expression) + +Map an expression over every pixel RGB value in the surface. Only works for +ARGB32 and RGB24 surfaces. + +The expression is an RPN expression in the OverLua Expression Evaluator +language, see expression-evaluator.txt for details. + +No additional functions are made available to the expression evaluator by +this function. + +The following new registers are made available to the expression evaluator: + R In range 0..1, red component. Input and output. + G Ditto, for green component. + B Ditto, for blue component. + X X-coordinate of pixel being processed. Input only. + Y Y-coordinate of pixel being processed. Input only. + + More filtering functions are planned, though no specifics yet. Wishes/suggestions are welcome, and so are patches to add more functions. diff --git a/OverLua/docs/test3.lua b/OverLua/docs/test3.lua index d36089865..1a53015fe 100644 --- a/OverLua/docs/test3.lua +++ b/OverLua/docs/test3.lua @@ -5,5 +5,10 @@ function render_frame(f, t) --raster.separable_filter(surf, {-1, 3, -1}, 1) --raster.directional_blur(surf, t, t/10) raster.radial_blur(surf, 200, 200, t/60) + raster.pixel_value_map(surf, "0 =R 1 G - =G") f.overlay_cairo_surface(surf, 0, 0) + + surf = cairo.image_surface_create(200, 200, "rgb24") + raster.pixel_value_map(surf, "rand =t0 t0 =R t0 =G t0 =B") + f.overlay_cairo_surface(surf, 20, 20) end diff --git a/OverLua/expression_engine.h b/OverLua/expression_engine.h index 34a4da00d..442cbf844 100644 --- a/OverLua/expression_engine.h +++ b/OverLua/expression_engine.h @@ -105,6 +105,9 @@ namespace ExpressionEngine { // Create a machine from a specification and a program source Machine(const Specification &spec, const char *source); + + // Create a blank machine + Machine() { } }; }; diff --git a/OverLua/raster_ops.cpp b/OverLua/raster_ops.cpp index 91bced849..e5fabfc56 100644 --- a/OverLua/raster_ops.cpp +++ b/OverLua/raster_ops.cpp @@ -30,6 +30,7 @@ #include #include +#include "expression_engine.h" #include "raster_ops.h" #include "../lua51/src/lauxlib.h" @@ -686,6 +687,82 @@ static int separable_filter(lua_State *L) } +static int pixel_value_map(lua_State *L) +{ + cairo_surface_t *surf = CheckSurface(L, 1); + const char *program = luaL_checkstring(L, 2); + + // Set up engine specs + ExpressionEngine::Specification spec; + spec.registers.resize(5); + spec.registers[0] = "R"; + spec.registers[1] = "G"; + spec.registers[2] = "B"; + spec.registers[3] = "X"; + spec.registers[4] = "Y"; + + // Compile program + ExpressionEngine::Machine machine; + try { + machine = ExpressionEngine::Machine(spec, program); + } + catch (const char *e) { + // This is a parse error + luaL_error(L, "Error in expression program near\"%s\"", e); + } + + // Init image + cairo_surface_flush(surf); + int width = cairo_image_surface_get_width(surf); + int height = cairo_image_surface_get_height(surf); + ptrdiff_t stride = (ptrdiff_t)cairo_image_surface_get_stride(surf); + unsigned char *data = cairo_image_surface_get_data(surf); + cairo_format_t format = cairo_image_surface_get_format(surf); + + if (format == CAIRO_FORMAT_ARGB32) { + BaseImage img(width, height, stride, data); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + PixelFormat::cairo_argb32 &p = img.Pixel(x, y); + machine.registers[0] = (double)p.R() / 255.0; + machine.registers[1] = (double)p.G() / 255.0; + machine.registers[2] = (double)p.B() / 255.0; + machine.registers[3] = x; + machine.registers[4] = y; + machine.Run(); + p.R() = (uint8_t)(machine.registers[0] * 255); + p.G() = (uint8_t)(machine.registers[1] * 255); + p.B() = (uint8_t)(machine.registers[2] * 255); + } + } + } + else if (format == CAIRO_FORMAT_RGB24) { + BaseImage img(width, height, stride, data); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + PixelFormat::cairo_rgb24 &p = img.Pixel(x, y); + machine.registers[0] = (double)p.R() / 255.0; + machine.registers[1] = (double)p.G() / 255.0; + machine.registers[2] = (double)p.B() / 255.0; + machine.registers[3] = x; + machine.registers[4] = y; + machine.Run(); + p.R() = (uint8_t)(machine.registers[0] * 255); + p.G() = (uint8_t)(machine.registers[1] * 255); + p.B() = (uint8_t)(machine.registers[2] * 255); + } + } + } + else { + luaL_error(L, "Unsupported pixel format"); + } + + cairo_surface_mark_dirty(surf); + + return 0; +} + + // Registration static luaL_Reg rasterlib[] = { @@ -693,6 +770,7 @@ static luaL_Reg rasterlib[] = { {"directional_blur", directional_blur}, {"radial_blur", radial_blur}, {"separable_filter", separable_filter}, {"invert", invert_image}, + {"pixel_value_map", pixel_value_map}, {NULL, NULL} };