/*****************/
/* 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 void
phong_shade (GimpVector3 *position,
             GimpVector3 *viewpoint,
             GimpVector3 *normal,
             GimpVector3 *lightposition,
             gdouble     *diff_col,
             gdouble     *light_col,
             LightType    light_type,
             gdouble     *diffuse_color)
{
  gdouble      specular_color[4];
  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 */
      /* =================================================== */

      for (gint i = 0; i < 4; i++)
        diffuse_color[i] = light_col[i];
      for (gint i = 0; i < 3; i++)
        diffuse_color[i] *= mapvals.material.diffuse_int;

      diffuse_color[0] *= diff_col[0];
      diffuse_color[1] *= diff_col[1];
      diffuse_color[2] *= diff_col[2];

      for (gint i = 0; i < 3; i++)
        diffuse_color[i] *= nl;
      for (gint i = 0; i < 4; i++)
        specular_color[i] = light_col[i];

      if (mapvals.material.metallic)  /* for metals, specular color = diffuse color */
        {
          specular_color[0] *= diff_col[0];
          specular_color[1] *= diff_col[1];
          specular_color[2] *= diff_col[2];
        }

      for (gint i = 0; i < 3; i++)
        {
          specular_color[i] *= mapvals.material.specular_ref;
          specular_color[i] *= rv;
        }

      for (gint i = 0; i < 3; i++)
        diffuse_color[i] += specular_color[i];
      for (gint i = 0; i < 4; i++)
        diffuse_color[i] = CLAMP (diffuse_color[i], 0.0, 1.0);
    }

  for (gint i = 0; i < 4; i++)
    diffuse_color[i] = CLAMP (diffuse_color[i], 0.0, 1.0);
}

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)
    {
      GimpDrawable *drawable = gimp_drawable_get_by_id (mapvals.bumpmap_id);

      bpp = gimp_drawable_get_bpp (drawable);
    }

  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 (gimp_drawable_get_by_id (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 (gimp_drawable_get_by_id (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 */
/*********************************************************************/

void
get_ray_color (GimpVector3 *position,
               gdouble     *color_sum)
{
  gdouble       color[4];
  gdouble       color_int[4];
  gdouble       light_color[4];
  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)
    {
      color_sum[3] = 0.0;
    }
  else
    {
      get_image_color (xf, yf, &f, color);

      for (gint i = 0; i < 4; i++)
        color_sum[i] = color[i];
      for (gint i = 0; i < 3; i++)
        color_sum[i] *= 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;

          for (gint i = 0; i < 4; i++)
            color_int[i] = mapvals.lightsource[k].color[i];
          for (gint i = 0; i < 3; i++)
            color_int[i] *= mapvals.lightsource[k].intensity;

          if (mapvals.bump_mapped == FALSE ||
              mapvals.bumpmap_id  == -1)
            {
              phong_shade (position,
                           &mapvals.viewpoint,
                           &mapvals.planenormal,
                           p,
                           color,
                           color_int,
                           mapvals.lightsource[k].type,
                           light_color);
            }
          else
            {
              normal = vertex_normals[1][(gint) RINT (xf)];

              phong_shade (position,
                           &mapvals.viewpoint,
                           &normal,
                           p,
                           color,
                           color_int,
                           mapvals.lightsource[k].type,
                           light_color);
            }

          for (gint i = 0; i < 3; i++)
            color_sum[i] += light_color[i];
        }
    }

  for (gint i = 0; i < 4; i++)
    color_sum[i] = CLAMP (color_sum[i], 0.0, 1.0);
}

void
get_ray_color_ref (GimpVector3 *position,
                   gdouble     *color_sum)
{
  gdouble      color_int[4];
  gdouble      light_color[4];
  gdouble      color[4], env_color[4];
  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)
    {
      color_sum[3] = 0.0;
    }
  else
    {
      get_image_color (xf, yf, &f, color);

      for (gint i = 0; i < 4; i++)
        color_sum[i] = color[i];
      for (gint i = 0; i < 3; i++)
        color_sum[i] *= 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;

          for (gint i = 0; i < 4; i++)
            color_int[i] = mapvals.lightsource[k].color[i];
          for (gint i = 0; i < 3; i++)
            color_int[i] *= mapvals.lightsource[k].intensity;

          phong_shade (position,
                       &mapvals.viewpoint,
                       &normal,
                       p,
                       color,
                       color_int,
                       mapvals.lightsource[0].type,
                       light_color);
        }

      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);
      peek_env_map (RINT (env_width * xf),
                    RINT (env_height * yf),
                    env_color);

      tmpval = mapvals.material.diffuse_int;
      mapvals.material.diffuse_int = 0.;

      phong_shade (position,
                   &mapvals.viewpoint,
                   &normal,
                   &r,
                   color,
                   env_color,
                   DIRECTIONAL_LIGHT,
                   light_color);

      mapvals.material.diffuse_int = tmpval;

      for (gint i = 0; i < 3; i++)
        color_sum[i] += light_color[i];
    }

  for (gint i = 0; i < 4; i++)
    color_sum[i] = CLAMP (color_sum[i], 0.0, 1.0);
}

void
get_ray_color_no_bilinear (GimpVector3 *position,
                           gdouble     *color_sum)
{
  gdouble       color[4];
  gdouble       color_int[4];
  gdouble       light_color[4];
  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)
    {
      color_sum[3] = 0.0;
    }
  else
    {
      peek (x, RINT (yf), color);

      for (gint i = 0; i < 4; i++)
        color_sum[i] = color[i];
      for (gint i = 0; i < 3; i++)
        color_sum[i] *= 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;

          for (gint i = 0; i < 4; i++)
            color_int[i] = mapvals.lightsource[k].color[i];
          for (gint i = 0; i < 3; i++)
            color_int[i] *= mapvals.lightsource[k].intensity;

          if (mapvals.bump_mapped == FALSE ||
              mapvals.bumpmap_id  == -1)
            {
              phong_shade (position,
                           &mapvals.viewpoint,
                           &mapvals.planenormal,
                           p,
                           color,
                           color_int,
                           mapvals.lightsource[k].type,
                           light_color);
            }
          else
            {
              normal = vertex_normals[1][x];

              phong_shade (position,
                           &mapvals.viewpoint,
                           &normal,
                           p,
                           color,
                           color_int,
                           mapvals.lightsource[k].type,
                           light_color);
            }

          for (gint i = 0; i < 3; i++)
            color_sum[i] += light_color[i];
        }
    }

  for (gint i = 0; i < 4; i++)
    color_sum[i] = CLAMP (color_sum[i], 0.0, 1.0);
}

void
get_ray_color_no_bilinear_ref (GimpVector3 *position,
                               gdouble     *color_sum)
{
  gdouble      color_int[4];
  gdouble      light_color[4];
  gdouble      color[4], env_color[4];
  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)
    {
      color_sum[3] = 0.0;
    }
  else
    {
      peek (RINT (xf), RINT (yf), color);

      for (gint i = 0; i < 4; i++)
        color_sum[i] = color[i];
      for (gint i = 0; i < 3; i++)
        color_sum[i] *= 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;

          for (gint i = 0; i < 4; i++)
            color_int[i] = mapvals.lightsource[k].color[i];
          for (gint i = 0; i < 3; i++)
            color_int[i] *= mapvals.lightsource[k].intensity;

          phong_shade (position,
                       &mapvals.viewpoint,
                       &normal,
                       p,
                       color,
                       color_int,
                       mapvals.lightsource[0].type,
                       light_color);
        }

      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);
      peek_env_map (RINT (env_width * xf),
                    RINT (env_height * yf),
                    env_color);

      tmpval = mapvals.material.diffuse_int;
      mapvals.material.diffuse_int = 0.0;

      phong_shade (position,
                   &mapvals.viewpoint,
                   &normal,
                   &r,
                   color,
                   env_color,
                   DIRECTIONAL_LIGHT,
                   light_color);

      mapvals.material.diffuse_int = tmpval;

      for (gint i = 0; i < 3; i++)
        color_sum[i] += light_color[i];
    }

  for (gint i = 0; i < 4; i++)
    color_sum[i] = CLAMP (color_sum[i], 0.0, 1.0);
}
