diff options
Diffstat (limited to 'plug-ins/lighting/lighting-image.c')
-rw-r--r-- | plug-ins/lighting/lighting-image.c | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/plug-ins/lighting/lighting-image.c b/plug-ins/lighting/lighting-image.c new file mode 100644 index 0000000..671176f --- /dev/null +++ b/plug-ins/lighting/lighting-image.c @@ -0,0 +1,410 @@ +/*************************************/ +/* GIMP image manipulation routines. */ +/*************************************/ + +#include "config.h" + +#include <gtk/gtk.h> + +#include <libgimp/gimp.h> + +#include "lighting-main.h" +#include "lighting-image.h" +#include "lighting-preview.h" +#include "lighting-ui.h" + + +gint32 input_drawable_id; +gint32 output_drawable_id; +GeglBuffer *source_buffer; +GeglBuffer *dest_buffer; + +gint32 bump_drawable_id; +GeglBuffer *bump_buffer; +const Babl *bump_format; + +gint32 env_drawable_id; +GeglBuffer *env_buffer; + +guchar *preview_rgb_data = NULL; +gint preview_rgb_stride; +cairo_surface_t *preview_surface = NULL; + +glong maxcounter; +gint width, height; +gint env_width, env_height; +GimpRGB background; + +gint border_x1, border_y1, border_x2, border_y2; + +guchar sinemap[256], spheremap[256], logmap[256]; + +/******************/ +/* Implementation */ +/******************/ + +guchar +peek_map (GeglBuffer *buffer, + const Babl *format, + gint x, + gint y) +{ + guchar data[4]; + guchar ret_val; + + gegl_buffer_sample (buffer, x, y, NULL, data, format, + GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); + + if (babl_format_get_bytes_per_pixel (format)) + { + ret_val = data[0]; + } + else + { + ret_val = (guchar)((float)((data[0] + data[1] + data[2])/3.0)); + } + + return ret_val; +} + +GimpRGB +peek (gint x, + gint y) +{ + GimpRGB color; + + gegl_buffer_sample (source_buffer, x, y, NULL, + &color, babl_format ("R'G'B'A double"), + GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); + + if (! babl_format_has_alpha (gegl_buffer_get_format (source_buffer))) + color.a = 1.0; + + return color; +} + +GimpRGB +peek_env_map (gint x, + gint y) +{ + GimpRGB color; + + if (x < 0) + x = 0; + else if (x >= env_width) + x = env_width - 1; + if (y < 0) + y = 0; + else if (y >= env_height) + y = env_height - 1; + + gegl_buffer_sample (env_buffer, x, y, NULL, + &color, babl_format ("R'G'B'A double"), + GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); + + color.a = 1.0; + + return color; +} + +void +poke (gint x, + gint y, + GimpRGB *color) +{ + if (x < 0) + x = 0; + else if (x >= width) + x = width - 1; + if (y < 0) + y = 0; + else if (y >= height) + y = height - 1; + + gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (x, y, 1, 1), 0, + babl_format ("R'G'B'A double"), color, + GEGL_AUTO_ROWSTRIDE); +} + +gint +check_bounds (gint x, + gint y) +{ + if (x < border_x1 || + y < border_y1 || + x >= border_x2 || + y >= border_y2) + return FALSE; + else + return TRUE; +} + +GimpVector3 +int_to_pos (gint x, + gint y) +{ + GimpVector3 pos; + + if (width >= height) + { + pos.x = (gdouble) x / (gdouble) width; + pos.y = (gdouble) y / (gdouble) width; + + pos.y += 0.5 * (1.0 - (gdouble) height / (gdouble) width); + } + else + { + pos.x = (gdouble) x / (gdouble) height; + pos.y = (gdouble) y / (gdouble) height; + + pos.x += 0.5 * (1.0 - (gdouble) width / (gdouble) height); + } + + pos.z = 0.0; + return pos; +} + +GimpVector3 +int_to_posf (gdouble x, + gdouble y) +{ + GimpVector3 pos; + + if (width >= height) + { + pos.x = x / (gdouble) width; + pos.y = y / (gdouble) width; + + pos.y += 0.5 * (1.0 - (gdouble) height / (gdouble) width); + } + else + { + pos.x = x / (gdouble) height; + pos.y = y / (gdouble) height; + + pos.x += 0.5 * (1.0 - (gdouble) width / (gdouble) height); + } + + pos.z = 0.0; + return pos; +} + +void +pos_to_int (gdouble x, + gdouble y, + gint *scr_x, + gint *scr_y) +{ + if (width >= height) + { + y -= 0.5 * (1.0 - (gdouble) height / (gdouble) width); + *scr_x = RINT ((x * (gdouble) width)); + *scr_y = RINT ((y * (gdouble) width)); + } + else + { + x -= 0.5 * (1.0 - (gdouble) width / (gdouble) height); + + *scr_x = RINT ((x * (gdouble) height)); + *scr_y = RINT ((y *(gdouble) height)); + } +} + +void +pos_to_float (gdouble x, + gdouble y, + gdouble *xf, + gdouble *yf) +{ + if (width >= height) + { + y -= 0.5 * (1.0 - (gdouble) height / (gdouble) width); + + *xf = x * (gdouble) (width-1); + *yf = y * (gdouble) (width-1); + } + else + { + x -= 0.5 * (1.0 - (gdouble) width / (gdouble) height); + + *xf = x * (gdouble) (height-1); + *yf = y * (gdouble) (height-1); + } +} + +/**********************************************/ +/* Compute the image color at pos (u,v) using */ +/* Quartics bilinear interpolation stuff. */ +/**********************************************/ + +GimpRGB +get_image_color (gdouble u, + gdouble v, + gint *inside) +{ + gint x1, y1, x2, y2; + GimpRGB p[4]; + + x1 = RINT (u); + y1 = RINT (v); + + if (check_bounds (x1, y1) == FALSE) + { + *inside = FALSE; + return background; + } + + x2 = (x1 + 1); + y2 = (y1 + 1); + + if (check_bounds (x2, y2) == FALSE) + { + *inside = TRUE; + return peek (x1, y1); + } + + *inside = TRUE; + p[0] = peek (x1, y1); + p[1] = peek (x2, y1); + p[2] = peek (x1, y2); + p[3] = peek (x2, y2); + + return gimp_bilinear_rgba (u, v, p); +} + +gdouble +get_map_value (GeglBuffer *buffer, + const Babl *format, + gdouble u, + gdouble v, + gint *inside) +{ + gint x1, y1, x2, y2; + gdouble p[4]; + + x1 = RINT (u); + y1 = RINT (v); + + x2 = (x1 + 1); + y2 = (y1 + 1); + + if (check_bounds (x2, y2) == FALSE) + { + *inside = TRUE; + return (gdouble) peek_map (buffer, format, x1, y1); + } + + *inside = TRUE; + p[0] = (gdouble) peek_map (buffer, format, x1, y1); + p[1] = (gdouble) peek_map (buffer, format, x2, y1); + p[2] = (gdouble) peek_map (buffer, format, x1, y2); + p[3] = (gdouble) peek_map (buffer, format, x2, y2); + + return gimp_bilinear (u, v, p); +} + +static void +compute_maps (void) +{ + gint x; + gdouble val, c, d; + + /* Compute Sine, Log and Spherical transfer function maps */ + /* ====================================================== */ + + c = 1.0 / 255.0; + d = 1.15 * 255.0; + + for (x = 0; x < 256; x++) + { + sinemap[x] = (guchar) (255.0 * (0.5 * (sin ((G_PI * c * (gdouble) x) - + 0.5 * G_PI) + + 1.0))); + spheremap[x] = (guchar) (255.0 * (sqrt (sin (G_PI * (gdouble) x / + 512.0)))); + val = (d * exp (-1.0 / (8.0 * c * ((gdouble) x + 5.0)))); + + if (val > 255.0) + val = 255.0; + logmap[x] = (guchar) val; + } +} + +/****************************************/ +/* Allocate memory for temporary images */ +/****************************************/ + +gint +image_setup (gint32 drawable_id, + gint interactive) +{ + gint w, h; + gboolean ret; + + compute_maps (); + + /* Get some useful info on the input drawable */ + /* ========================================== */ + + input_drawable_id = drawable_id; + output_drawable_id = drawable_id; + + ret = gimp_drawable_mask_intersect (drawable_id, + &border_x1, &border_y1, &w, &h); + + border_x2 = border_x1 + w; + border_y2 = border_y1 + h; + + if (! ret) + return FALSE; + + width = gimp_drawable_width (input_drawable_id); + height = gimp_drawable_height (input_drawable_id); + + source_buffer = gimp_drawable_get_buffer (input_drawable_id); + + maxcounter = (glong) width * (glong) height; + + if (interactive) + { + preview_rgb_stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, + PREVIEW_WIDTH); + preview_rgb_data = g_new0 (guchar, preview_rgb_stride * PREVIEW_HEIGHT); + preview_surface = cairo_image_surface_create_for_data (preview_rgb_data, + CAIRO_FORMAT_RGB24, + PREVIEW_WIDTH, + PREVIEW_HEIGHT, + preview_rgb_stride); + } + + return TRUE; +} + +void +bumpmap_setup (gint32 bumpmap_id) +{ + if (bumpmap_id != -1) + { + if (! bump_buffer) + { + bump_buffer = gimp_drawable_get_buffer (bumpmap_id); + } + + if (gimp_drawable_is_rgb (bumpmap_id)) + bump_format = babl_format ("R'G'B' u8"); + else + bump_format = babl_format ("Y' u8"); /* FIXME */ + } +} + +void +envmap_setup (gint32 envmap_id) +{ + if (envmap_id != -1 && ! env_buffer) + { + env_width = gimp_drawable_width (envmap_id); + env_height = gimp_drawable_height (envmap_id); + + env_buffer = gimp_drawable_get_buffer (envmap_id); + } +} |