857 lines
23 KiB
C
857 lines
23 KiB
C
/*****************/
|
|
/* Shading stuff */
|
|
/*****************/
|
|
|
|
#include "config.h"
|
|
|
|
#include <libpika/pika.h>
|
|
|
|
#include "lighting-main.h"
|
|
#include "lighting-image.h"
|
|
#include "lighting-shade.h"
|
|
|
|
|
|
static PikaVector3 *triangle_normals[2] = { NULL, NULL };
|
|
static PikaVector3 *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 PikaRGB
|
|
phong_shade (PikaVector3 *position,
|
|
PikaVector3 *viewpoint,
|
|
PikaVector3 *normal,
|
|
PikaVector3 *lightposition,
|
|
PikaRGB *diff_col,
|
|
PikaRGB *light_col,
|
|
LightType light_type)
|
|
{
|
|
PikaRGB diffuse_color, specular_color;
|
|
gdouble nl, rv, dist;
|
|
PikaVector3 l, v, n, lnormal, h;
|
|
|
|
/* Compute ambient intensity */
|
|
/* ========================= */
|
|
|
|
n = *normal;
|
|
|
|
/* Compute (N*L) term of Phong's equation */
|
|
/* ====================================== */
|
|
|
|
if (light_type == POINT_LIGHT)
|
|
pika_vector3_sub (&l, lightposition, position);
|
|
else
|
|
{
|
|
l = *lightposition;
|
|
pika_vector3_normalize (&l);
|
|
}
|
|
|
|
dist = pika_vector3_length (&l);
|
|
|
|
if (dist != 0.0)
|
|
pika_vector3_mul (&l, 1.0 / dist);
|
|
|
|
nl = MAX (0., 2.0 * pika_vector3_inner_product (&n, &l));
|
|
|
|
lnormal = l;
|
|
pika_vector3_normalize (&lnormal);
|
|
|
|
if (nl >= 0.0)
|
|
{
|
|
/* Compute (R*V)^alpha term of Phong's equation */
|
|
/* ============================================ */
|
|
|
|
pika_vector3_sub (&v, viewpoint, position);
|
|
pika_vector3_normalize (&v);
|
|
|
|
pika_vector3_add (&h, &lnormal, &v);
|
|
pika_vector3_normalize (&h);
|
|
|
|
rv = MAX (0.01, pika_vector3_inner_product (&n, &h));
|
|
rv = pow (rv, mapvals.material.highlight);
|
|
rv *= nl;
|
|
|
|
/* Compute diffuse and specular intensity contribution */
|
|
/* =================================================== */
|
|
|
|
diffuse_color = *light_col;
|
|
pika_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;
|
|
pika_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;
|
|
}
|
|
pika_rgb_multiply (&specular_color, mapvals.material.specular_ref);
|
|
pika_rgb_multiply (&specular_color, rv);
|
|
|
|
pika_rgb_add (&diffuse_color, &specular_color);
|
|
pika_rgb_clamp (&diffuse_color);
|
|
}
|
|
|
|
pika_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 (PikaVector3, 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)
|
|
{
|
|
PikaDrawable *drawable = pika_drawable_get_by_id (mapvals.bumpmap_id);
|
|
|
|
bpp = pika_drawable_get_bpp (drawable);
|
|
}
|
|
|
|
bumprow = g_new (guchar, w * bpp);
|
|
|
|
triangle_normals[0] = g_new (PikaVector3, (w << 1) + 2);
|
|
triangle_normals[1] = g_new (PikaVector3, (w << 1) + 2);
|
|
|
|
for (n = 0; n < (w << 1) + 1; n++)
|
|
{
|
|
pika_vector3_set (&triangle_normals[0][n], 0.0, 0.0, 1.0);
|
|
pika_vector3_set (&triangle_normals[1][n], 0.0, 0.0, 1.0);
|
|
}
|
|
|
|
for (n = 0; n < w; n++)
|
|
{
|
|
pika_vector3_set (&vertex_normals[0][n], 0.0, 0.0, 1.0);
|
|
pika_vector3_set (&vertex_normals[1][n], 0.0, 0.0, 1.0);
|
|
pika_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)
|
|
{
|
|
PikaVector3 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 (pika_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] = pika_vector3_cross_product (&p2, &p1);
|
|
triangle_normals[1][i+1] = pika_vector3_cross_product (&p3, &p2);
|
|
|
|
pika_vector3_normalize (&triangle_normals[1][i]);
|
|
pika_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)
|
|
{
|
|
PikaVector3 *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 (pika_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] = pika_vector3_cross_product (&p2, &p1);
|
|
triangle_normals[1][i+1] = pika_vector3_cross_product (&p3, &p2);
|
|
|
|
pika_vector3_normalize (&triangle_normals[1][i]);
|
|
pika_vector3_normalize (&triangle_normals[1][i+1]);
|
|
|
|
i += 2;
|
|
}
|
|
|
|
/* Compute vertex normals */
|
|
/* ====================== */
|
|
|
|
i = 0;
|
|
pika_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)
|
|
{
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[0][i-1]);
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[0][i-2]);
|
|
nv += 2;
|
|
}
|
|
|
|
if (y < pre_h)
|
|
{
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[1][i-1]);
|
|
nv++;
|
|
}
|
|
}
|
|
|
|
if (n < pre_w)
|
|
{
|
|
if (y > 0)
|
|
{
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[0][i]);
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[0][i+1]);
|
|
nv += 2;
|
|
}
|
|
|
|
if (y < pre_h)
|
|
{
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[1][i]);
|
|
pika_vector3_add (&normal, &normal, &triangle_normals[1][i+1]);
|
|
nv += 2;
|
|
}
|
|
}
|
|
|
|
pika_vector3_mul (&normal, 1.0 / (gdouble) nv);
|
|
pika_vector3_normalize (&normal);
|
|
vertex_normals[1][n] = normal;
|
|
|
|
i += 2;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Compute the reflected ray given the normalized normal and ins. vec. */
|
|
/***********************************************************************/
|
|
|
|
static PikaVector3
|
|
compute_reflected_ray (PikaVector3 *normal,
|
|
PikaVector3 *view)
|
|
{
|
|
PikaVector3 ref;
|
|
gdouble nl;
|
|
|
|
nl = 2.0 * pika_vector3_inner_product (normal, view);
|
|
|
|
ref = *normal;
|
|
|
|
pika_vector3_mul (&ref, nl);
|
|
pika_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 (PikaVector3 *normal,
|
|
gdouble *u,
|
|
gdouble *v)
|
|
{
|
|
static gdouble alpha, fac;
|
|
static PikaVector3 cross_prod;
|
|
static PikaVector3 firstaxis = { 1.0, 0.0, 0.0 };
|
|
static PikaVector3 secondaxis = { 0.0, 1.0, 0.0 };
|
|
|
|
alpha = acos (-pika_vector3_inner_product (&secondaxis, normal));
|
|
|
|
*v = alpha / G_PI;
|
|
|
|
if (*v == 0.0 || *v == 1.0)
|
|
{
|
|
*u = 0.0;
|
|
}
|
|
else
|
|
{
|
|
fac = pika_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 = pika_vector3_cross_product (&secondaxis, &firstaxis);
|
|
|
|
if (pika_vector3_inner_product (&cross_prod, normal) < 0.0)
|
|
*u = 1.0 - *u;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/* These routines computes the color of the surface at a given point */
|
|
/*********************************************************************/
|
|
|
|
PikaRGB
|
|
get_ray_color (PikaVector3 *position)
|
|
{
|
|
PikaRGB color;
|
|
PikaRGB color_int;
|
|
PikaRGB color_sum;
|
|
PikaRGB light_color;
|
|
gint x, f;
|
|
gdouble xf, yf;
|
|
PikaVector3 normal, *p;
|
|
gint k;
|
|
|
|
pos_to_float (position->x, position->y, &xf, &yf);
|
|
|
|
x = RINT (xf);
|
|
|
|
if (mapvals.transparent_background && heights[1][x] == 0)
|
|
{
|
|
pika_rgb_set_alpha (&color_sum, 0.0);
|
|
}
|
|
else
|
|
{
|
|
color = get_image_color (xf, yf, &f);
|
|
|
|
color_sum = color;
|
|
pika_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;
|
|
pika_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);
|
|
}
|
|
|
|
pika_rgb_add (&color_sum, &light_color);
|
|
}
|
|
}
|
|
|
|
pika_rgb_clamp (&color_sum);
|
|
|
|
return color_sum;
|
|
}
|
|
|
|
PikaRGB
|
|
get_ray_color_ref (PikaVector3 *position)
|
|
{
|
|
PikaRGB color_sum;
|
|
PikaRGB color_int;
|
|
PikaRGB light_color;
|
|
PikaRGB color, env_color;
|
|
gint x, f;
|
|
gdouble xf, yf;
|
|
PikaVector3 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)];
|
|
}
|
|
|
|
pika_vector3_normalize (&normal);
|
|
|
|
if (mapvals.transparent_background && heights[1][x] == 0)
|
|
{
|
|
pika_rgb_set_alpha (&color_sum, 0.0);
|
|
}
|
|
else
|
|
{
|
|
color = get_image_color (xf, yf, &f);
|
|
color_sum = color;
|
|
pika_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;
|
|
pika_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
|
|
|
|
light_color = phong_shade (position,
|
|
&mapvals.viewpoint,
|
|
&normal,
|
|
p,
|
|
&color,
|
|
&color_int,
|
|
mapvals.lightsource[0].type);
|
|
}
|
|
|
|
pika_vector3_sub (&v, &mapvals.viewpoint, position);
|
|
pika_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;
|
|
|
|
pika_rgb_add (&color_sum, &light_color);
|
|
}
|
|
|
|
pika_rgb_clamp (&color_sum);
|
|
|
|
return color_sum;
|
|
}
|
|
|
|
PikaRGB
|
|
get_ray_color_no_bilinear (PikaVector3 *position)
|
|
{
|
|
PikaRGB color;
|
|
PikaRGB color_int;
|
|
PikaRGB color_sum;
|
|
PikaRGB light_color;
|
|
gint x;
|
|
gdouble xf, yf;
|
|
PikaVector3 normal, *p;
|
|
gint k;
|
|
|
|
pos_to_float (position->x, position->y, &xf, &yf);
|
|
|
|
x = RINT (xf);
|
|
|
|
if (mapvals.transparent_background && heights[1][x] == 0)
|
|
{
|
|
pika_rgb_set_alpha (&color_sum, 0.0);
|
|
}
|
|
else
|
|
{
|
|
color = peek (x, RINT (yf));
|
|
|
|
color_sum = color;
|
|
pika_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;
|
|
pika_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);
|
|
}
|
|
|
|
pika_rgb_add (&color_sum, &light_color);
|
|
}
|
|
}
|
|
|
|
pika_rgb_clamp (&color_sum);
|
|
|
|
return color_sum;
|
|
}
|
|
|
|
PikaRGB
|
|
get_ray_color_no_bilinear_ref (PikaVector3 *position)
|
|
{
|
|
PikaRGB color_sum;
|
|
PikaRGB color_int;
|
|
PikaRGB light_color;
|
|
PikaRGB color, env_color;
|
|
gint x;
|
|
gdouble xf, yf;
|
|
PikaVector3 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)];
|
|
}
|
|
|
|
pika_vector3_normalize (&normal);
|
|
|
|
if (mapvals.transparent_background && heights[1][x] == 0)
|
|
{
|
|
pika_rgb_set_alpha (&color_sum, 0.0);
|
|
}
|
|
else
|
|
{
|
|
color = peek (RINT (xf), RINT (yf));
|
|
color_sum = color;
|
|
pika_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;
|
|
pika_rgb_multiply (&color_int, mapvals.lightsource[k].intensity);
|
|
|
|
light_color = phong_shade (position,
|
|
&mapvals.viewpoint,
|
|
&normal,
|
|
p,
|
|
&color,
|
|
&color_int,
|
|
mapvals.lightsource[0].type);
|
|
}
|
|
|
|
pika_vector3_sub (&v, &mapvals.viewpoint, position);
|
|
pika_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;
|
|
|
|
pika_rgb_add (&color_sum, &light_color);
|
|
}
|
|
|
|
pika_rgb_clamp (&color_sum);
|
|
|
|
return color_sum;
|
|
}
|