forked from mia/Aegisub
Implement raster.pixel_value_map function using expression evaluator. Seems to work correct.
Originally committed to SVN as r1507.
This commit is contained in:
parent
3b5e953c70
commit
a460743682
5 changed files with 112 additions and 1 deletions
|
@ -217,4 +217,10 @@ else return the third argument.
|
||||||
Sample programs
|
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.
|
||||||
|
|
|
@ -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.
|
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.
|
More filtering functions are planned, though no specifics yet.
|
||||||
|
|
||||||
Wishes/suggestions are welcome, and so are patches to add more functions.
|
Wishes/suggestions are welcome, and so are patches to add more functions.
|
||||||
|
|
|
@ -5,5 +5,10 @@ function render_frame(f, t)
|
||||||
--raster.separable_filter(surf, {-1, 3, -1}, 1)
|
--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)
|
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)
|
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
|
end
|
||||||
|
|
|
@ -105,6 +105,9 @@ namespace ExpressionEngine {
|
||||||
|
|
||||||
// Create a machine from a specification and a program source
|
// Create a machine from a specification and a program source
|
||||||
Machine(const Specification &spec, const char *source);
|
Machine(const Specification &spec, const char *source);
|
||||||
|
|
||||||
|
// Create a blank machine
|
||||||
|
Machine() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "expression_engine.h"
|
||||||
#include "raster_ops.h"
|
#include "raster_ops.h"
|
||||||
#include "../lua51/src/lauxlib.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<PixelFormat::cairo_argb32> 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<PixelFormat::cairo_rgb24> 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
|
// Registration
|
||||||
|
|
||||||
static luaL_Reg rasterlib[] = {
|
static luaL_Reg rasterlib[] = {
|
||||||
|
@ -693,6 +770,7 @@ static luaL_Reg rasterlib[] = {
|
||||||
{"directional_blur", directional_blur}, {"radial_blur", radial_blur},
|
{"directional_blur", directional_blur}, {"radial_blur", radial_blur},
|
||||||
{"separable_filter", separable_filter},
|
{"separable_filter", separable_filter},
|
||||||
{"invert", invert_image},
|
{"invert", invert_image},
|
||||||
|
{"pixel_value_map", pixel_value_map},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue