summaryrefslogtreecommitdiffstats
path: root/plug-ins/lighting/lighting-shade.c
diff options
context:
space:
mode:
Diffstat (limited to 'plug-ins/lighting/lighting-shade.c')
-rw-r--r--plug-ins/lighting/lighting-shade.c838
1 files changed, 838 insertions, 0 deletions
diff --git a/plug-ins/lighting/lighting-shade.c b/plug-ins/lighting/lighting-shade.c
new file mode 100644
index 0000000..70443d9
--- /dev/null
+++ b/plug-ins/lighting/lighting-shade.c
@@ -0,0 +1,838 @@
+/*****************/
+/* Shading stuff */
+/*****************/
+
+#include "config.h"
+
+#include <libgimp/gimp.h>
+
+#include "lighting-main.h"
+#include "lighting-image.h"
+#include "lighting-shade.h"
+
+
+static GimpVector3 *triangle_normals[2] = { NULL, NULL };
+static GimpVector3 *vertex_normals[3] = { NULL, NULL, NULL };
+static gdouble *heights[3] = { NULL, NULL, NULL };
+static gdouble xstep, ystep;
+static guchar *bumprow = NULL;
+
+static gint pre_w = -1;
+static gint pre_h = -1;
+
+/*****************/
+/* Phong shading */
+/*****************/
+
+static GimpRGB
+phong_shade (GimpVector3 *position,
+ GimpVector3 *viewpoint,
+ GimpVector3 *normal,
+ GimpVector3 *lightposition,
+ GimpRGB *diff_col,
+ GimpRGB *light_col,
+ LightType light_type)
+{
+ GimpRGB diffuse_color, specular_color;
+ gdouble nl, rv, dist;
+ GimpVector3 l, v, n, lnormal, h;
+
+ /* Compute ambient intensity */
+ /* ========================= */
+
+ n = *normal;
+
+ /* Compute (N*L) term of Phong's equation */
+ /* ====================================== */
+
+ if (light_type == POINT_LIGHT)
+ gimp_vector3_sub (&l, lightposition, position);
+ else
+ {
+ l = *lightposition;
+ gimp_vector3_normalize (&l);
+ }
+
+ dist = gimp_vector3_length (&l);
+
+ if (dist != 0.0)
+ gimp_vector3_mul (&l, 1.0 / dist);
+
+ nl = MAX (0., 2.0 * gimp_vector3_inner_product (&n, &l));
+
+ lnormal = l;
+ gimp_vector3_normalize (&lnormal);
+
+ if (nl >= 0.0)
+ {
+ /* Compute (R*V)^alpha term of Phong's equation */
+ /* ============================================ */
+
+ gimp_vector3_sub (&v, viewpoint, position);
+ gimp_vector3_normalize (&v);
+
+ gimp_vector3_add (&h, &lnormal, &v);
+ gimp_vector3_normalize (&h);
+
+ rv = MAX (0.01, gimp_vector3_inner_product (&n, &h));
+ rv = pow (rv, mapvals.material.highlight);
+ rv *= nl;
+
+ /* Compute diffuse and specular intensity contribution */
+ /* =================================================== */
+
+ diffuse_color = *light_col;
+ gimp_rgb_multiply (&diffuse_color, mapvals.material.diffuse_int);
+ diffuse_color.r *= diff_col->r;
+ diffuse_color.g *= diff_col->g;
+ diffuse_color.b *= diff_col->b;
+ gimp_rgb_multiply (&diffuse_color, nl);
+
+ specular_color = *light_col;
+ if (mapvals.material.metallic) /* for metals, specular color = diffuse color */
+ {
+ specular_color.r *= diff_col->r;
+ specular_color.g *= diff_col->g;
+ specular_color.b *= diff_col->b;
+ }
+ gimp_rgb_multiply (&specular_color, mapvals.material.specular_ref);
+ gimp_rgb_multiply (&specular_color, rv);
+
+ gimp_rgb_add (&diffuse_color, &specular_color);
+ gimp_rgb_clamp (&diffuse_color);
+ }
+
+ gimp_rgb_clamp (&diffuse_color);
+
+ return diffuse_color;
+}
+
+void
+precompute_init (gint w,
+ gint h)
+{
+ gint n;
+ gint bpp=1;
+
+ xstep = 1.0 / (gdouble) width;
+ ystep = 1.0 / (gdouble) height;
+
+ pre_w = w;
+ pre_h = h;
+
+ for (n = 0; n < 3; n++)
+ {
+ if (vertex_normals[n] != NULL)
+ g_free (vertex_normals[n]);
+
+ if (heights[n] != NULL)
+ g_free (heights[n]);
+
+ heights[n] = g_new (gdouble, w);
+ vertex_normals[n] = g_new (GimpVector3, w);
+ }
+
+ for (n = 0; n < 2; n++)
+ if (triangle_normals[n] != NULL)
+ g_free (triangle_normals[n]);
+
+ g_clear_pointer (&bumprow, g_free);
+
+ if (mapvals.bumpmap_id != -1)
+ {
+ bpp = gimp_drawable_bpp(mapvals.bumpmap_id);
+ }
+
+ bumprow = g_new (guchar, w * bpp);
+
+ triangle_normals[0] = g_new (GimpVector3, (w << 1) + 2);
+ triangle_normals[1] = g_new (GimpVector3, (w << 1) + 2);
+
+ for (n = 0; n < (w << 1) + 1; n++)
+ {
+ gimp_vector3_set (&triangle_normals[0][n], 0.0, 0.0, 1.0);
+ gimp_vector3_set (&triangle_normals[1][n], 0.0, 0.0, 1.0);
+ }
+
+ for (n = 0; n < w; n++)
+ {
+ gimp_vector3_set (&vertex_normals[0][n], 0.0, 0.0, 1.0);
+ gimp_vector3_set (&vertex_normals[1][n], 0.0, 0.0, 1.0);
+ gimp_vector3_set (&vertex_normals[2][n], 0.0, 0.0, 1.0);
+ heights[0][n] = 0.0;
+ heights[1][n] = 0.0;
+ heights[2][n] = 0.0;
+ }
+}
+
+
+/* Interpol linearly height[2] and triangle_normals[1]
+ * using the next row
+ */
+void
+interpol_row (gint x1,
+ gint x2,
+ gint y)
+{
+ GimpVector3 p1, p2, p3;
+ gint n, i;
+ guchar *map = NULL;
+ gint bpp = 1;
+ guchar *bumprow1 = NULL;
+ guchar *bumprow2 = NULL;
+
+ if (mapvals.bumpmap_id != -1)
+ {
+ bumpmap_setup (mapvals.bumpmap_id);
+
+ bpp = babl_format_get_bytes_per_pixel (bump_format);
+ }
+
+ bumprow1 = g_new0 (guchar, pre_w * bpp);
+ bumprow2 = g_new0 (guchar, pre_w * bpp);
+
+ gegl_buffer_get (bump_buffer, GEGL_RECTANGLE (x1, y, x2 - x1, 1), 1.0,
+ bump_format, bumprow1,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ gegl_buffer_get (bump_buffer, GEGL_RECTANGLE (x1, y - 1, x2 - x1, 1), 1.0,
+ bump_format, bumprow2,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ if (mapvals.bumpmaptype > 0)
+ {
+ switch (mapvals.bumpmaptype)
+ {
+ case 1:
+ map = logmap;
+ break;
+ case 2:
+ map = sinemap;
+ break;
+ default:
+ map = spheremap;
+ break;
+ }
+ }
+
+ for (n = 0; n < (x2 - x1); n++)
+ {
+ gdouble diff;
+ guchar mapval;
+ guchar mapval1, mapval2;
+
+ if (bpp>1)
+ {
+ mapval1 = (guchar)((float)((bumprow1[n * bpp] +bumprow1[n * bpp +1] + bumprow1[n * bpp + 2])/3.0 )) ;
+ mapval2 = (guchar)((float)((bumprow2[n * bpp] +bumprow2[n * bpp +1] + bumprow2[n * bpp + 2])/3.0 )) ;
+ }
+ else
+ {
+ mapval1 = bumprow1[n * bpp];
+ mapval2 = bumprow2[n * bpp];
+ }
+
+ diff = mapval1 - mapval2;
+ mapval = (guchar) CLAMP (mapval1 + diff, 0.0, 255.0);
+
+ if (mapvals.bumpmaptype > 0)
+ {
+ heights[1][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval1] / 255.0;
+ heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0;
+ }
+ else
+ {
+ heights[1][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval1 / 255.0;
+ heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0;
+ }
+ }
+
+ i = 0;
+ for (n = 0; n < (x2 - x1 - 1); n++)
+ {
+ /* heights rows 1 and 2 are inverted */
+ p1.x = 0.0;
+ p1.y = ystep;
+ p1.z = heights[1][n] - heights[2][n];
+
+ p2.x = xstep;
+ p2.y = ystep;
+ p2.z = heights[1][n+1] - heights[2][n];
+
+ p3.x = xstep;
+ p3.y = 0.0;
+ p3.z = heights[2][n+1] - heights[2][n];
+
+ triangle_normals[1][i] = gimp_vector3_cross_product (&p2, &p1);
+ triangle_normals[1][i+1] = gimp_vector3_cross_product (&p3, &p2);
+
+ gimp_vector3_normalize (&triangle_normals[1][i]);
+ gimp_vector3_normalize (&triangle_normals[1][i+1]);
+
+ i += 2;
+ }
+
+ g_free (bumprow1);
+ g_free (bumprow2);
+}
+
+/********************************************/
+/* Compute triangle and then vertex normals */
+/********************************************/
+
+
+void
+precompute_normals (gint x1,
+ gint x2,
+ gint y)
+{
+ GimpVector3 *tmpv, p1, p2, p3, normal;
+ gdouble *tmpd;
+ gint n, i, nv;
+ guchar *map = NULL;
+ gint bpp = 1;
+ guchar mapval;
+
+
+ /* First, compute the heights */
+ /* ========================== */
+
+ tmpv = triangle_normals[0];
+ triangle_normals[0] = triangle_normals[1];
+ triangle_normals[1] = tmpv;
+
+ tmpv = vertex_normals[0];
+ vertex_normals[0] = vertex_normals[1];
+ vertex_normals[1] = vertex_normals[2];
+ vertex_normals[2] = tmpv;
+
+ tmpd = heights[0];
+ heights[0] = heights[1];
+ heights[1] = heights[2];
+ heights[2] = tmpd;
+
+ if (mapvals.bumpmap_id != -1)
+ {
+ bumpmap_setup (mapvals.bumpmap_id);
+
+ bpp = babl_format_get_bytes_per_pixel (bump_format);
+ }
+
+ gegl_buffer_get (bump_buffer, GEGL_RECTANGLE (x1, y, x2 - x1, 1), 1.0,
+ bump_format, bumprow,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ if (mapvals.bumpmaptype > 0)
+ {
+ switch (mapvals.bumpmaptype)
+ {
+ case 1:
+ map = logmap;
+ break;
+ case 2:
+ map = sinemap;
+ break;
+ default:
+ map = spheremap;
+ break;
+ }
+
+ for (n = 0; n < (x2 - x1); n++)
+ {
+ if (bpp > 1)
+ {
+ mapval = (guchar)((float)((bumprow[n * bpp + 0] +
+ bumprow[n * bpp + 1] +
+ bumprow[n * bpp + 2]) /3.0));
+ }
+ else
+ {
+ mapval = bumprow[n * bpp];
+ }
+
+ heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) map[mapval] / 255.0;
+ }
+ }
+ else
+ {
+ for (n = 0; n < (x2 - x1); n++)
+ {
+ if (bpp>1)
+ {
+ mapval = (guchar)((float)((bumprow[n * bpp + 0] +
+ bumprow[n * bpp + 1] +
+ bumprow[n * bpp + 2]) / 3.0));
+ }
+ else
+ {
+ mapval = bumprow[n * bpp];
+ }
+
+ heights[2][n] = (gdouble) mapvals.bumpmax * (gdouble) mapval / 255.0;
+ }
+ }
+
+ /* Compute triangle normals */
+ /* ======================== */
+
+ i = 0;
+ for (n = 0; n < (x2 - x1 - 1); n++)
+ {
+ p1.x = 0.0;
+ p1.y = ystep;
+ p1.z = heights[2][n] - heights[1][n];
+
+ p2.x = xstep;
+ p2.y = ystep;
+ p2.z = heights[2][n+1] - heights[1][n];
+
+ p3.x = xstep;
+ p3.y = 0.0;
+ p3.z = heights[1][n+1] - heights[1][n];
+
+ triangle_normals[1][i] = gimp_vector3_cross_product (&p2, &p1);
+ triangle_normals[1][i+1] = gimp_vector3_cross_product (&p3, &p2);
+
+ gimp_vector3_normalize (&triangle_normals[1][i]);
+ gimp_vector3_normalize (&triangle_normals[1][i+1]);
+
+ i += 2;
+ }
+
+ /* Compute vertex normals */
+ /* ====================== */
+
+ i = 0;
+ gimp_vector3_set (&normal, 0.0, 0.0, 0.0);
+
+ for (n = 0; n < (x2 - x1 - 1); n++)
+ {
+ nv = 0;
+
+ if (n > 0)
+ {
+ if (y > 0)
+ {
+ gimp_vector3_add (&normal, &normal, &triangle_normals[0][i-1]);
+ gimp_vector3_add (&normal, &normal, &triangle_normals[0][i-2]);
+ nv += 2;
+ }
+
+ if (y < pre_h)
+ {
+ gimp_vector3_add (&normal, &normal, &triangle_normals[1][i-1]);
+ nv++;
+ }
+ }
+
+ if (n <pre_w)
+ {
+ if (y > 0)
+ {
+ gimp_vector3_add (&normal, &normal, &triangle_normals[0][i]);
+ gimp_vector3_add (&normal, &normal, &triangle_normals[0][i+1]);
+ nv += 2;
+ }
+
+ if (y < pre_h)
+ {
+ gimp_vector3_add (&normal, &normal, &triangle_normals[1][i]);
+ gimp_vector3_add (&normal, &normal, &triangle_normals[1][i+1]);
+ nv += 2;
+ }
+ }
+
+ gimp_vector3_mul (&normal, 1.0 / (gdouble) nv);
+ gimp_vector3_normalize (&normal);
+ vertex_normals[1][n] = normal;
+
+ i += 2;
+ }
+}
+
+/***********************************************************************/
+/* Compute the reflected ray given the normalized normal and ins. vec. */
+/***********************************************************************/
+
+static GimpVector3
+compute_reflected_ray (GimpVector3 *normal,
+ GimpVector3 *view)
+{
+ GimpVector3 ref;
+ gdouble nl;
+
+ nl = 2.0 * gimp_vector3_inner_product (normal, view);
+
+ ref = *normal;
+
+ gimp_vector3_mul (&ref, nl);
+ gimp_vector3_sub (&ref, &ref, view);
+
+ return ref;
+}
+
+/************************************************************************/
+/* Given the NorthPole, Equator and a third vector (normal) compute */
+/* the conversion from spherical coordinates to image space coordinates */
+/************************************************************************/
+
+static void
+sphere_to_image (GimpVector3 *normal,
+ gdouble *u,
+ gdouble *v)
+{
+ static gdouble alpha, fac;
+ static GimpVector3 cross_prod;
+ static GimpVector3 firstaxis = { 1.0, 0.0, 0.0 };
+ static GimpVector3 secondaxis = { 0.0, 1.0, 0.0 };
+
+ alpha = acos (-gimp_vector3_inner_product (&secondaxis, normal));
+
+ *v = alpha / G_PI;
+
+ if (*v==0.0 || *v==1.0)
+ {
+ *u = 0.0;
+ }
+ else
+ {
+ fac = gimp_vector3_inner_product (&firstaxis, normal) / sin (alpha);
+
+ /* Make sure that we map to -1.0..1.0 (take care of rounding errors) */
+ /* ================================================================= */
+
+ if (fac>1.0)
+ fac = 1.0;
+ else if (fac<-1.0)
+ fac = -1.0;
+
+ *u = acos (fac) / (2.0 * G_PI);
+
+ cross_prod = gimp_vector3_cross_product (&secondaxis, &firstaxis);
+
+ if (gimp_vector3_inner_product (&cross_prod, normal) < 0.0)
+ *u = 1.0 - *u;
+ }
+}
+
+/*********************************************************************/
+/* These routines computes the color of the surface at a given point */
+/*********************************************************************/
+
+GimpRGB
+get_ray_color (GimpVector3 *position)
+{
+ GimpRGB color;
+ GimpRGB color_int;
+ GimpRGB color_sum;
+ GimpRGB light_color;
+ gint x, f;
+ gdouble xf, yf;
+ GimpVector3 normal, *p;
+ gint k;
+
+ pos_to_float (position->x, position->y, &xf, &yf);
+
+ x = RINT (xf);
+
+ if (mapvals.transparent_background && heights[1][x] == 0)
+ {
+ gimp_rgb_set_alpha (&color_sum, 0.0);
+ }
+ else
+ {
+ color = get_image_color (xf, yf, &f);
+
+ color_sum = color;
+ gimp_rgb_multiply (&color_sum, mapvals.material.ambient_int);
+
+ for (k = 0; k < NUM_LIGHTS; k++)
+ {
+ if (!mapvals.lightsource[k].active
+ || mapvals.lightsource[k].type == NO_LIGHT)
+ continue;
+ else if (mapvals.lightsource[k].type == POINT_LIGHT)
+ p = &mapvals.lightsource[k].position;
+ else
+ p = &mapvals.lightsource[k].direction;
+
+ color_int = mapvals.lightsource[k].color;
+ gimp_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
+
+ if (mapvals.bump_mapped == FALSE || mapvals.bumpmap_id == -1)
+ {
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &mapvals.planenormal,
+ p,
+ &color,
+ &color_int,
+ mapvals.lightsource[k].type);
+ }
+ else
+ {
+ normal = vertex_normals[1][(gint) RINT (xf)];
+
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &normal,
+ p,
+ &color,
+ &color_int,
+ mapvals.lightsource[k].type);
+ }
+
+ gimp_rgb_add (&color_sum, &light_color);
+ }
+ }
+
+ gimp_rgb_clamp (&color_sum);
+ return color_sum;
+}
+
+GimpRGB
+get_ray_color_ref (GimpVector3 *position)
+{
+ GimpRGB color_sum;
+ GimpRGB color_int;
+ GimpRGB light_color;
+ GimpRGB color, env_color;
+ gint x, f;
+ gdouble xf, yf;
+ GimpVector3 normal, *p, v, r;
+ gint k;
+ gdouble tmpval;
+
+ pos_to_float (position->x, position->y, &xf, &yf);
+
+ x = RINT (xf);
+
+ if (mapvals.bump_mapped == FALSE || mapvals.bumpmap_id == -1)
+ normal = mapvals.planenormal;
+ else
+ normal = vertex_normals[1][(gint) RINT (xf)];
+ gimp_vector3_normalize (&normal);
+
+ if (mapvals.transparent_background && heights[1][x] == 0)
+ {
+ gimp_rgb_set_alpha (&color_sum, 0.0);
+ }
+ else
+ {
+ color = get_image_color (xf, yf, &f);
+ color_sum = color;
+ gimp_rgb_multiply (&color_sum, mapvals.material.ambient_int);
+
+ for (k = 0; k < NUM_LIGHTS; k++)
+ {
+ p = &mapvals.lightsource[k].direction;
+
+ if (!mapvals.lightsource[k].active
+ || mapvals.lightsource[k].type == NO_LIGHT)
+ continue;
+ else if (mapvals.lightsource[k].type == POINT_LIGHT)
+ p = &mapvals.lightsource[k].position;
+
+ color_int = mapvals.lightsource[k].color;
+ gimp_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
+
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &normal,
+ p,
+ &color,
+ &color_int,
+ mapvals.lightsource[0].type);
+ }
+
+ gimp_vector3_sub (&v, &mapvals.viewpoint, position);
+ gimp_vector3_normalize (&v);
+
+ r = compute_reflected_ray (&normal, &v);
+
+ /* Get color in the direction of r */
+ /* =============================== */
+
+ sphere_to_image (&r, &xf, &yf);
+ env_color = peek_env_map (RINT (env_width * xf),
+ RINT (env_height * yf));
+
+ tmpval = mapvals.material.diffuse_int;
+ mapvals.material.diffuse_int = 0.;
+
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &normal,
+ &r,
+ &color,
+ &env_color,
+ DIRECTIONAL_LIGHT);
+
+ mapvals.material.diffuse_int = tmpval;
+
+ gimp_rgb_add (&color_sum, &light_color);
+ }
+
+ gimp_rgb_clamp (&color_sum);
+ return color_sum;
+}
+
+GimpRGB
+get_ray_color_no_bilinear (GimpVector3 *position)
+{
+ GimpRGB color;
+ GimpRGB color_int;
+ GimpRGB color_sum;
+ GimpRGB light_color;
+ gint x;
+ gdouble xf, yf;
+ GimpVector3 normal, *p;
+ gint k;
+
+
+ pos_to_float (position->x, position->y, &xf, &yf);
+
+ x = RINT (xf);
+
+ if (mapvals.transparent_background && heights[1][x] == 0)
+ {
+ gimp_rgb_set_alpha (&color_sum, 0.0);
+ }
+ else
+ {
+ color = peek (x, RINT (yf));
+
+ color_sum = color;
+ gimp_rgb_multiply (&color_sum, mapvals.material.ambient_int);
+
+ for (k = 0; k < NUM_LIGHTS; k++)
+ {
+ p = &mapvals.lightsource[k].direction;
+
+ if (!mapvals.lightsource[k].active
+ || mapvals.lightsource[k].type == NO_LIGHT)
+ continue;
+ else if (mapvals.lightsource[k].type == POINT_LIGHT)
+ p = &mapvals.lightsource[k].position;
+
+ color_int = mapvals.lightsource[k].color;
+ gimp_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
+
+ if (mapvals.bump_mapped == FALSE || mapvals.bumpmap_id == -1)
+ {
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &mapvals.planenormal,
+ p,
+ &color,
+ &color_int,
+ mapvals.lightsource[k].type);
+ }
+ else
+ {
+ normal = vertex_normals[1][x];
+
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &normal,
+ p,
+ &color,
+ &color_int,
+ mapvals.lightsource[k].type);
+ }
+
+ gimp_rgb_add (&color_sum, &light_color);
+ }
+ }
+
+ gimp_rgb_clamp (&color_sum);
+ return color_sum;
+}
+
+GimpRGB
+get_ray_color_no_bilinear_ref (GimpVector3 *position)
+{
+ GimpRGB color_sum;
+ GimpRGB color_int;
+ GimpRGB light_color;
+ GimpRGB color, env_color;
+ gint x;
+ gdouble xf, yf;
+ GimpVector3 normal, *p, v, r;
+ gint k;
+ gdouble tmpval;
+
+ pos_to_float (position->x, position->y, &xf, &yf);
+
+ x = RINT (xf);
+
+ if (mapvals.bump_mapped == FALSE || mapvals.bumpmap_id == -1)
+ normal = mapvals.planenormal;
+ else
+ normal = vertex_normals[1][(gint) RINT (xf)];
+ gimp_vector3_normalize (&normal);
+
+ if (mapvals.transparent_background && heights[1][x] == 0)
+ {
+ gimp_rgb_set_alpha (&color_sum, 0.0);
+ }
+ else
+ {
+ color = peek (RINT (xf), RINT (yf));
+ color_sum = color;
+ gimp_rgb_multiply (&color_sum, mapvals.material.ambient_int);
+
+ for (k = 0; k < NUM_LIGHTS; k++)
+ {
+ p = &mapvals.lightsource[k].direction;
+
+ if (!mapvals.lightsource[k].active
+ || mapvals.lightsource[k].type == NO_LIGHT)
+ continue;
+ else if (mapvals.lightsource[k].type == POINT_LIGHT)
+ p = &mapvals.lightsource[k].position;
+
+ color_int = mapvals.lightsource[k].color;
+ gimp_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
+
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &normal,
+ p,
+ &color,
+ &color_int,
+ mapvals.lightsource[0].type);
+ }
+
+ gimp_vector3_sub (&v, &mapvals.viewpoint, position);
+ gimp_vector3_normalize (&v);
+
+ r = compute_reflected_ray (&normal, &v);
+
+ /* Get color in the direction of r */
+ /* =============================== */
+
+ sphere_to_image (&r, &xf, &yf);
+ env_color = peek_env_map (RINT (env_width * xf),
+ RINT (env_height * yf));
+
+ tmpval = mapvals.material.diffuse_int;
+ mapvals.material.diffuse_int = 0.;
+
+ light_color = phong_shade (position,
+ &mapvals.viewpoint,
+ &normal,
+ &r,
+ &color,
+ &env_color,
+ DIRECTIONAL_LIGHT);
+
+ mapvals.material.diffuse_int = tmpval;
+
+ gimp_rgb_add (&color_sum, &light_color);
+ }
+
+ gimp_rgb_clamp (&color_sum);
+
+ return color_sum;
+}