gimp/plug-ins/lighting/lighting-image.c

427 lines
9.1 KiB
C
Raw Normal View History

1998-06-11 06:04:59 +00:00
/*************************************/
/* 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"
1998-06-11 06:04:59 +00:00
GimpDrawable *input_drawable;
GimpDrawable *output_drawable;
GeglBuffer *source_buffer;
GeglBuffer *dest_buffer;
1998-06-11 06:04:59 +00:00
GimpDrawable *bump_drawable;
GeglBuffer *bump_buffer;
const Babl *bump_format;
1998-06-11 06:04:59 +00:00
GimpDrawable *env_drawable;
GeglBuffer *env_buffer;
1998-06-11 06:04:59 +00:00
guchar *preview_rgb_data = NULL;
gint preview_rgb_stride;
cairo_surface_t *preview_surface = NULL;
1998-06-11 06:04:59 +00:00
2019-07-10 12:19:13 +02:00
glong maxcounter;
gint width, height;
gint env_width, env_height;
gdouble background[4];
1998-06-11 06:04:59 +00:00
gint border_x1, border_y1, border_x2, border_y2;
1998-06-11 06:04:59 +00:00
guchar sinemap[256], spheremap[256], logmap[256];
1998-06-11 06:04:59 +00:00
/******************/
/* Implementation */
/******************/
guchar
2019-07-10 12:19:13 +02:00
peek_map (GeglBuffer *buffer,
const Babl *format,
gint x,
gint y)
1998-06-11 06:04:59 +00:00
{
guchar data[4];
guchar ret_val;
2019-07-10 12:19:13 +02:00
gegl_buffer_sample (buffer, x, y, NULL, data, format,
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
2019-07-10 12:19:13 +02:00
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;
1998-06-11 06:04:59 +00:00
}
void
peek (gint x,
gint y,
gdouble *color)
1998-06-11 06:04:59 +00:00
{
2019-07-10 12:19:13 +02:00
gegl_buffer_sample (source_buffer, x, y, NULL,
color, babl_format ("R'G'B'A double"),
2019-07-10 12:19:13 +02:00
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
1998-06-11 06:04:59 +00:00
2019-07-10 12:19:13 +02:00
if (! babl_format_has_alpha (gegl_buffer_get_format (source_buffer)))
color[3] = 1.0;
1998-06-11 06:04:59 +00:00
}
void
peek_env_map (gint x,
gint y,
gdouble *color)
1998-06-11 06:04:59 +00:00
{
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;
1998-06-11 06:04:59 +00:00
2019-07-10 12:19:13 +02:00
gegl_buffer_sample (env_buffer, x, y, NULL,
color, babl_format ("R'G'B'A double"),
2019-07-10 12:19:13 +02:00
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
1998-06-11 06:04:59 +00:00
color[3] = 1.0;
1998-06-11 06:04:59 +00:00
}
void
poke (gint x,
gint y,
gdouble *color)
1998-06-11 06:04:59 +00:00
{
if (x < 0)
x = 0;
else if (x >= width)
x = width - 1;
if (y < 0)
y = 0;
else if (y >= height)
y = height - 1;
2019-07-10 12:19:13 +02:00
gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (x, y, 1, 1), 0,
babl_format ("R'G'B'A double"), color,
GEGL_AUTO_ROWSTRIDE);
1998-06-11 06:04:59 +00:00
}
gint
check_bounds (gint x,
gint y)
1998-06-11 06:04:59 +00:00
{
2019-07-10 12:19:13 +02:00
if (x < border_x1 ||
y < border_y1 ||
x >= border_x2 ||
y >= border_y2)
return FALSE;
1998-06-11 06:04:59 +00:00
else
return TRUE;
1998-06-11 06:04:59 +00:00
}
GimpVector3
int_to_pos (gint x,
gint y)
1998-06-11 06:04:59 +00:00
{
GimpVector3 pos;
1998-06-11 06:04:59 +00:00
if (width >= height)
1998-06-11 06:04:59 +00:00
{
pos.x = (gdouble) x / (gdouble) width;
pos.y = (gdouble) y / (gdouble) width;
1998-06-11 06:04:59 +00:00
pos.y += 0.5 * (1.0 - (gdouble) height / (gdouble) width);
1998-06-11 06:04:59 +00:00
}
else
{
pos.x = (gdouble) x / (gdouble) height;
pos.y = (gdouble) y / (gdouble) height;
1998-06-11 06:04:59 +00:00
pos.x += 0.5 * (1.0 - (gdouble) width / (gdouble) height);
1998-06-11 06:04:59 +00:00
}
pos.z = 0.0;
return pos;
1998-06-11 06:04:59 +00:00
}
GimpVector3
int_to_posf (gdouble x,
gdouble y)
1998-06-11 06:04:59 +00:00
{
GimpVector3 pos;
1998-06-11 06:04:59 +00:00
if (width >= height)
1998-06-11 06:04:59 +00:00
{
pos.x = x / (gdouble) width;
pos.y = y / (gdouble) width;
1998-06-11 06:04:59 +00:00
pos.y += 0.5 * (1.0 - (gdouble) height / (gdouble) width);
1998-06-11 06:04:59 +00:00
}
else
{
pos.x = x / (gdouble) height;
pos.y = y / (gdouble) height;
1998-06-11 06:04:59 +00:00
pos.x += 0.5 * (1.0 - (gdouble) width / (gdouble) height);
1998-06-11 06:04:59 +00:00
}
pos.z = 0.0;
return pos;
1998-06-11 06:04:59 +00:00
}
void
pos_to_int (gdouble x,
gdouble y,
gint *scr_x,
gint *scr_y)
1998-06-11 06:04:59 +00:00
{
if (width >= height)
1998-06-11 06:04:59 +00:00
{
y -= 0.5 * (1.0 - (gdouble) height / (gdouble) width);
*scr_x = RINT ((x * (gdouble) width));
*scr_y = RINT ((y * (gdouble) width));
1998-06-11 06:04:59 +00:00
}
else
{
x -= 0.5 * (1.0 - (gdouble) width / (gdouble) height);
1998-06-11 06:04:59 +00:00
*scr_x = RINT ((x * (gdouble) height));
*scr_y = RINT ((y *(gdouble) height));
1998-06-11 06:04:59 +00:00
}
}
void
pos_to_float (gdouble x,
gdouble y,
gdouble *xf,
gdouble *yf)
1998-06-11 06:04:59 +00:00
{
if (width >= height)
1998-06-11 06:04:59 +00:00
{
y -= 0.5 * (1.0 - (gdouble) height / (gdouble) width);
*xf = x * (gdouble) (width-1);
*yf = y * (gdouble) (width-1);
1998-06-11 06:04:59 +00:00
}
else
{
x -= 0.5 * (1.0 - (gdouble) width / (gdouble) height);
1998-06-11 06:04:59 +00:00
*xf = x * (gdouble) (height-1);
*yf = y * (gdouble) (height-1);
1998-06-11 06:04:59 +00:00
}
}
/**********************************************/
/* Compute the image color at pos (u,v) using */
/* Quartics bilinear interpolation stuff. */
/**********************************************/
void
get_image_color (gdouble u,
gdouble v,
gint *inside,
gdouble *color)
1998-06-11 06:04:59 +00:00
{
gint x1;
gint y1;
gint x2;
gint y2;
gdouble p[4];
gdouble pixels[16];
x1 = RINT (u);
y1 = RINT (v);
1998-06-11 06:04:59 +00:00
if (check_bounds (x1, y1) == FALSE)
1998-06-11 06:04:59 +00:00
{
*inside = FALSE;
for (gint i = 0; i < 4; i++)
color[i] = background[i];
return;
1998-06-11 06:04:59 +00:00
}
x2 = (x1 + 1);
y2 = (y1 + 1);
if (check_bounds (x2, y2) == FALSE)
{
*inside = TRUE;
peek (x1, y1, color);
return;
}
1998-06-11 06:04:59 +00:00
*inside = TRUE;
peek (x1, y1, p);
for (gint i = 0; i < 4; i++)
pixels[i] = p[i];
peek (x2, y1, p);
for (gint i = 0; i < 4; i++)
pixels[i + 4] = p[i];
peek (x1, y2, p);
for (gint i = 0; i < 4; i++)
pixels[i + 8] = p[i];
peek (x2, y2, p);
for (gint i = 0; i < 4; i++)
pixels[i + 12] = p[i];
gimp_bilinear_rgb (u, v, pixels, TRUE, color);
1998-06-11 06:04:59 +00:00
}
gdouble
2019-07-10 12:19:13 +02:00
get_map_value (GeglBuffer *buffer,
const Babl *format,
gdouble u,
gdouble v,
gint *inside)
1998-06-11 06:04:59 +00:00
{
gint x1, y1, x2, y2;
gdouble p[4];
x1 = RINT (u);
y1 = RINT (v);
1998-06-11 06:04:59 +00:00
x2 = (x1 + 1);
y2 = (y1 + 1);
if (check_bounds (x2, y2) == FALSE)
{
*inside = TRUE;
2019-07-10 12:19:13 +02:00
return (gdouble) peek_map (buffer, format, x1, y1);
}
1998-06-11 06:04:59 +00:00
*inside = TRUE;
2019-07-10 12:19:13 +02:00
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);
1998-06-11 06:04:59 +00:00
return gimp_bilinear (u, v, p);
1998-06-11 06:04:59 +00:00
}
static void
compute_maps (void)
1998-06-11 06:04:59 +00:00
{
gint x;
gdouble val, c, d;
1998-06-11 06:04:59 +00:00
/* Compute Sine, Log and Spherical transfer function maps */
1998-06-11 06:04:59 +00:00
/* ====================================================== */
c = 1.0 / 255.0;
d = 1.15 * 255.0;
for (x = 0; x < 256; x++)
1998-06-11 06:04:59 +00:00
{
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;
1998-06-11 06:04:59 +00:00
}
}
/****************************************/
/* Allocate memory for temporary images */
/****************************************/
gint
image_setup (GimpDrawable *drawable,
gint interactive)
1998-06-11 06:04:59 +00:00
{
2019-07-10 12:19:13 +02:00
gint w, h;
gboolean ret;
compute_maps ();
1998-06-11 06:04:59 +00:00
/* Get some useful info on the input drawable */
/* ========================================== */
input_drawable = drawable;
output_drawable = drawable;
1998-06-11 06:04:59 +00:00
ret = gimp_drawable_mask_intersect (drawable,
&border_x1, &border_y1, &w, &h);
border_x2 = border_x1 + w;
border_y2 = border_y1 + h;
if (! ret)
return FALSE;
1998-06-11 06:04:59 +00:00
width = gimp_drawable_get_width (input_drawable);
height = gimp_drawable_get_height (input_drawable);
1998-06-11 06:04:59 +00:00
source_buffer = gimp_drawable_get_buffer (input_drawable);
1998-06-11 06:04:59 +00:00
maxcounter = (glong) width * (glong) height;
1998-06-11 06:04:59 +00:00
if (interactive)
1998-06-11 06:04:59 +00:00
{
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);
1998-06-11 06:04:59 +00:00
}
return TRUE;
1998-06-11 06:04:59 +00:00
}
2019-07-10 12:19:13 +02:00
void
bumpmap_setup (GimpDrawable *bumpmap)
2019-07-10 12:19:13 +02:00
{
if (bumpmap)
2019-07-10 12:19:13 +02:00
{
gboolean has_alpha = gimp_drawable_has_alpha (bumpmap);
if (! bump_buffer)
{
bump_buffer = gimp_drawable_get_buffer (bumpmap);
}
2019-07-10 12:19:13 +02:00
if (gimp_drawable_is_rgb (bumpmap))
bump_format = has_alpha ? babl_format ("R'aG'aB'aA u8") :
babl_format ("R'G'B' u8");
2019-07-10 12:19:13 +02:00
else
bump_format = has_alpha ? babl_format ("Y'aA u8") : /* FIXME */
babl_format ("Y' u8");
2019-07-10 12:19:13 +02:00
}
}
void
envmap_setup (GimpDrawable *envmap)
2019-07-10 12:19:13 +02:00
{
if (envmap && ! env_buffer)
2019-07-10 12:19:13 +02:00
{
env_width = gimp_drawable_get_width (envmap);
env_height = gimp_drawable_get_height (envmap);
2019-07-10 12:19:13 +02:00
env_buffer = gimp_drawable_get_buffer (envmap);
2019-07-10 12:19:13 +02:00
}
}