1255 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1255 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*****************/
 | |
| /* Shading stuff */
 | |
| /*****************/
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include <libpika/pika.h>
 | |
| #include <libpika/pikaui.h>
 | |
| 
 | |
| #include "map-object-apply.h"
 | |
| #include "map-object-main.h"
 | |
| #include "map-object-image.h"
 | |
| #include "map-object-shade.h"
 | |
| 
 | |
| 
 | |
| static gdouble     bx1, by1, bx2, by2;
 | |
| get_ray_color_func get_ray_color;
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   gdouble     u, v;
 | |
|   gdouble     t;
 | |
|   PikaVector3 s;
 | |
|   PikaVector3 n;
 | |
|   gint        face;
 | |
| } FaceIntersectInfo;
 | |
| 
 | |
| /*****************/
 | |
| /* Phong shading */
 | |
| /*****************/
 | |
| 
 | |
| static PikaRGB
 | |
| phong_shade (PikaVector3 *pos,
 | |
|              PikaVector3 *viewpoint,
 | |
|              PikaVector3 *normal,
 | |
|              PikaRGB     *diff_col,
 | |
|              PikaRGB     *spec_col,
 | |
|              LightType    type)
 | |
| {
 | |
|   PikaRGB       ambientcolor, diffusecolor, specularcolor;
 | |
|   gdouble      NL, RV, dist;
 | |
|   PikaVector3  L, NN, V, N;
 | |
|   PikaVector3  *light;
 | |
| 
 | |
|   light = mapvals.lightsource.type == DIRECTIONAL_LIGHT
 | |
|     ? &mapvals.lightsource.direction
 | |
|     : &mapvals.lightsource.position,
 | |
| 
 | |
|   /* Compute ambient intensity */
 | |
|   /* ========================= */
 | |
| 
 | |
|   N = *normal;
 | |
|   ambientcolor = *diff_col;
 | |
|   pika_rgb_multiply (&ambientcolor, mapvals.material.ambient_int);
 | |
| 
 | |
|   /* Compute (N*L) term of Phong's equation */
 | |
|   /* ====================================== */
 | |
| 
 | |
|   if (type == POINT_LIGHT)
 | |
|     pika_vector3_sub (&L, light, pos);
 | |
|   else
 | |
|     L = *light;
 | |
| 
 | |
|   dist = pika_vector3_length (&L);
 | |
| 
 | |
|   if (dist != 0.0)
 | |
|     pika_vector3_mul (&L, 1.0 / dist);
 | |
| 
 | |
|   NL = 2.0 * pika_vector3_inner_product (&N, &L);
 | |
| 
 | |
|   if (NL >= 0.0)
 | |
|     {
 | |
|       /* Compute (R*V)^alpha term of Phong's equation */
 | |
|       /* ============================================ */
 | |
| 
 | |
|       pika_vector3_sub (&V, viewpoint, pos);
 | |
|       pika_vector3_normalize (&V);
 | |
| 
 | |
|       pika_vector3_mul (&N, NL);
 | |
|       pika_vector3_sub (&NN, &N, &L);
 | |
|       RV = pika_vector3_inner_product (&NN, &V);
 | |
|       RV = 0.0 < RV ? pow (RV, mapvals.material.highlight) : 0.0;
 | |
| 
 | |
|       /* Compute diffuse and specular intensity contribution */
 | |
|       /* =================================================== */
 | |
| 
 | |
|       diffusecolor = *diff_col;
 | |
|       pika_rgb_multiply (&diffusecolor, mapvals.material.diffuse_ref);
 | |
|       pika_rgb_multiply (&diffusecolor, NL);
 | |
| 
 | |
|       specularcolor = *spec_col;
 | |
|       pika_rgb_multiply (&specularcolor, mapvals.material.specular_ref);
 | |
|       pika_rgb_multiply (&specularcolor, RV);
 | |
| 
 | |
|       pika_rgb_add (&diffusecolor, &specularcolor);
 | |
|       pika_rgb_multiply (&diffusecolor, mapvals.material.diffuse_int);
 | |
|       pika_rgb_clamp (&diffusecolor);
 | |
| 
 | |
|       pika_rgb_add (&ambientcolor, &diffusecolor);
 | |
|     }
 | |
| 
 | |
|   return ambientcolor;
 | |
| }
 | |
| 
 | |
| static gint
 | |
| plane_intersect (PikaVector3 *dir,
 | |
|                  PikaVector3 *viewp,
 | |
|                  PikaVector3 *ipos,
 | |
|                  gdouble     *u,
 | |
|                  gdouble     *v)
 | |
| {
 | |
|   static gdouble det, det1, det2, det3, t;
 | |
| 
 | |
|   imat[0][0] = dir->x;
 | |
|   imat[1][0] = dir->y;
 | |
|   imat[2][0] = dir->z;
 | |
| 
 | |
|   /* Compute determinant of the first 3x3 sub matrix (denominator) */
 | |
|   /* ============================================================= */
 | |
| 
 | |
|   det = (imat[0][0] * imat[1][1] * imat[2][2] +
 | |
|          imat[0][1] * imat[1][2] * imat[2][0] +
 | |
|          imat[0][2] * imat[1][0] * imat[2][1] -
 | |
|          imat[0][2] * imat[1][1] * imat[2][0] -
 | |
|          imat[0][0] * imat[1][2] * imat[2][1] -
 | |
|          imat[2][2] * imat[0][1] * imat[1][0]);
 | |
| 
 | |
|   /* If the determinant is non-zero, a intersection point exists */
 | |
|   /* =========================================================== */
 | |
| 
 | |
|   if (det != 0.0)
 | |
|     {
 | |
|       /* Now, lets compute the numerator determinants (wow ;) */
 | |
|       /* ==================================================== */
 | |
| 
 | |
|       det1 = (imat[0][3] * imat[1][1] * imat[2][2] +
 | |
|               imat[0][1] * imat[1][2] * imat[2][3] +
 | |
|               imat[0][2] * imat[1][3] * imat[2][1] -
 | |
|               imat[0][2] * imat[1][1] * imat[2][3] -
 | |
|               imat[1][2] * imat[2][1] * imat[0][3] -
 | |
|               imat[2][2] * imat[0][1] * imat[1][3]);
 | |
| 
 | |
|       det2 = (imat[0][0] * imat[1][3] * imat[2][2] +
 | |
|               imat[0][3] * imat[1][2] * imat[2][0] +
 | |
|               imat[0][2] * imat[1][0] * imat[2][3] -
 | |
|               imat[0][2] * imat[1][3] * imat[2][0] -
 | |
|               imat[1][2] * imat[2][3] * imat[0][0] -
 | |
|               imat[2][2] * imat[0][3] * imat[1][0]);
 | |
| 
 | |
|       det3 = (imat[0][0] * imat[1][1] * imat[2][3] +
 | |
|               imat[0][1] * imat[1][3] * imat[2][0] +
 | |
|               imat[0][3] * imat[1][0] * imat[2][1] -
 | |
|               imat[0][3] * imat[1][1] * imat[2][0] -
 | |
|               imat[1][3] * imat[2][1] * imat[0][0] -
 | |
|               imat[2][3] * imat[0][1] * imat[1][0]);
 | |
| 
 | |
|       /* Now we have the simultaneous solutions. Lets compute the unknowns */
 | |
|       /* (skip u&v if t is <0, this means the intersection is behind us)  */
 | |
|       /* ================================================================ */
 | |
| 
 | |
|       t = det1 / det;
 | |
| 
 | |
|       if (t > 0.0)
 | |
|         {
 | |
|           *u = 1.0 + ((det2 / det) - 0.5);
 | |
|           *v = 1.0 + ((det3 / det) - 0.5);
 | |
| 
 | |
|                 ipos->x = viewp->x + t * dir->x;
 | |
|           ipos->y = viewp->y + t * dir->y;
 | |
|           ipos->z = viewp->z + t * dir->z;
 | |
| 
 | |
|           return TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * These routines computes the color of the surface
 | |
|  * of the plane at a given point
 | |
|  *****************************************************************************/
 | |
| 
 | |
| PikaRGB
 | |
| get_ray_color_plane (PikaVector3 *pos)
 | |
| {
 | |
|   PikaRGB color = background;
 | |
| 
 | |
|   static gint         inside = FALSE;
 | |
|   static PikaVector3  ray, spos;
 | |
|   static gdouble      vx, vy;
 | |
| 
 | |
|   /* Construct a line from our VP to the point */
 | |
|   /* ========================================= */
 | |
| 
 | |
|   pika_vector3_sub (&ray, pos, &mapvals.viewpoint);
 | |
|   pika_vector3_normalize (&ray);
 | |
| 
 | |
|   /* Check for intersection. This is a quasi ray-tracer. */
 | |
|   /* =================================================== */
 | |
| 
 | |
|   if (plane_intersect (&ray, &mapvals.viewpoint, &spos, &vx, &vy) == TRUE)
 | |
|     {
 | |
|       color = get_image_color (vx, vy, &inside);
 | |
| 
 | |
|       if (color.a != 0.0 && inside == TRUE &&
 | |
|           mapvals.lightsource.type != NO_LIGHT)
 | |
|         {
 | |
|           /* Compute shading at this point */
 | |
|           /* ============================= */
 | |
| 
 | |
|           color = phong_shade (&spos,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &mapvals.normal,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   if (mapvals.transparent_background == FALSE && color.a < 1.0)
 | |
|     {
 | |
|       pika_rgb_composite (&color, &background,
 | |
|                           PIKA_RGB_COMPOSITE_BEHIND);
 | |
|     }
 | |
| 
 | |
|   return color;
 | |
| }
 | |
| 
 | |
| /***********************************************************************/
 | |
| /* Given the NorthPole, Equator and a third vector (normal) compute    */
 | |
| /* the conversion from spherical oordinates to image space coordinates */
 | |
| /***********************************************************************/
 | |
| 
 | |
| static void
 | |
| sphere_to_image (PikaVector3 *normal,
 | |
|                  gdouble     *u,
 | |
|                  gdouble     *v)
 | |
| {
 | |
|   static gdouble      alpha, fac;
 | |
|   static PikaVector3  cross_prod;
 | |
| 
 | |
|   alpha = acos (-pika_vector3_inner_product (&mapvals.secondaxis, normal));
 | |
| 
 | |
|   *v = alpha / G_PI;
 | |
| 
 | |
|   if (*v == 0.0 || *v == 1.0)
 | |
|     {
 | |
|       *u = 0.0;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       fac = (pika_vector3_inner_product (&mapvals.firstaxis, normal) /
 | |
|              sin (alpha));
 | |
| 
 | |
|       /* Make sure that we map to -1.0..1.0 (take care of rounding errors) */
 | |
|       /* ================================================================= */
 | |
| 
 | |
|       fac = CLAMP (fac, -1.0, 1.0);
 | |
| 
 | |
|       *u = acos (fac) / (2.0 * G_PI);
 | |
| 
 | |
|       cross_prod = pika_vector3_cross_product (&mapvals.secondaxis,
 | |
|                                                &mapvals.firstaxis);
 | |
| 
 | |
|       if (pika_vector3_inner_product (&cross_prod, normal) < 0.0)
 | |
|         *u = 1.0 - *u;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /***************************************************/
 | |
| /* Compute intersection point with sphere (if any) */
 | |
| /***************************************************/
 | |
| 
 | |
| static gint
 | |
| sphere_intersect (PikaVector3 *dir,
 | |
|                   PikaVector3 *viewp,
 | |
|                   PikaVector3 *spos1,
 | |
|                   PikaVector3 *spos2)
 | |
| {
 | |
|   static gdouble      alpha, beta, tau, s1, s2, tmp;
 | |
|   static PikaVector3  t;
 | |
| 
 | |
|   pika_vector3_sub (&t, &mapvals.position, viewp);
 | |
| 
 | |
|   alpha = pika_vector3_inner_product (dir, &t);
 | |
|   beta  = pika_vector3_inner_product (&t, &t);
 | |
| 
 | |
|   tau = alpha * alpha - beta + mapvals.radius * mapvals.radius;
 | |
| 
 | |
|   if (tau >= 0.0)
 | |
|     {
 | |
|       tau = sqrt (tau);
 | |
|       s1 = alpha + tau;
 | |
|       s2 = alpha - tau;
 | |
| 
 | |
|       if (s2 < s1)
 | |
|         {
 | |
|           tmp = s1;
 | |
|           s1 = s2;
 | |
|           s2 = tmp;
 | |
|         }
 | |
| 
 | |
|       spos1->x = viewp->x + s1 * dir->x;
 | |
|       spos1->y = viewp->y + s1 * dir->y;
 | |
|       spos1->z = viewp->z + s1 * dir->z;
 | |
|       spos2->x = viewp->x + s2 * dir->x;
 | |
|       spos2->y = viewp->y + s2 * dir->y;
 | |
|       spos2->z = viewp->z + s2 * dir->z;
 | |
| 
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * These routines computes the color of the surface
 | |
|  * of the sphere at a given point
 | |
|  *****************************************************************************/
 | |
| 
 | |
| PikaRGB
 | |
| get_ray_color_sphere (PikaVector3 *pos)
 | |
| {
 | |
|   PikaRGB color = background;
 | |
| 
 | |
|   static PikaRGB      color2;
 | |
|   static gint         inside = FALSE;
 | |
|   static PikaVector3  normal, ray, spos1, spos2;
 | |
|   static gdouble      vx, vy;
 | |
| 
 | |
|   /* Check if ray is within the bounding box */
 | |
|   /* ======================================= */
 | |
| 
 | |
|   if (pos->x<bx1 || pos->x>bx2 || pos->y<by1 || pos->y>by2)
 | |
|     return color;
 | |
| 
 | |
|   /* Construct a line from our VP to the point */
 | |
|   /* ========================================= */
 | |
| 
 | |
|   pika_vector3_sub (&ray, pos, &mapvals.viewpoint);
 | |
|   pika_vector3_normalize (&ray);
 | |
| 
 | |
|   /* Check for intersection. This is a quasi ray-tracer. */
 | |
|   /* =================================================== */
 | |
| 
 | |
|   if (sphere_intersect (&ray, &mapvals.viewpoint, &spos1, &spos2) == TRUE)
 | |
|     {
 | |
|       /* Compute spherical to rectangular mapping */
 | |
|       /* ======================================== */
 | |
| 
 | |
|       pika_vector3_sub (&normal, &spos1, &mapvals.position);
 | |
|       pika_vector3_normalize (&normal);
 | |
|       sphere_to_image (&normal, &vx, &vy);
 | |
|       color = get_image_color (vx, vy, &inside);
 | |
| 
 | |
|       /* Check for total transparency... */
 | |
|       /* =============================== */
 | |
| 
 | |
|       if (color.a < 1.0)
 | |
|         {
 | |
|           /* Hey, we can see  through here!      */
 | |
|           /* Lets see what's on the other side.. */
 | |
|           /* =================================== */
 | |
| 
 | |
|           color = phong_shade (&spos1,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &normal,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
| 
 | |
|           pika_vector3_sub (&normal, &spos2, &mapvals.position);
 | |
|           pika_vector3_normalize (&normal);
 | |
|           sphere_to_image (&normal, &vx, &vy);
 | |
|           color2 = get_image_color (vx, vy, &inside);
 | |
| 
 | |
|           /* Make the normal point inwards */
 | |
|           /* ============================= */
 | |
| 
 | |
|           pika_vector3_mul (&normal, -1.0);
 | |
| 
 | |
|           color2 = phong_shade (&spos2,
 | |
|                                 &mapvals.viewpoint,
 | |
|                                 &normal,
 | |
|                                 &color2,
 | |
|                                 &mapvals.lightsource.color,
 | |
|                                 mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color2);
 | |
| 
 | |
|           /* Compute a mix of the first and second colors */
 | |
|           /* ============================================ */
 | |
| 
 | |
|           pika_rgb_composite (&color, &color2, PIKA_RGB_COMPOSITE_NORMAL);
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|       else if (color.a != 0.0 &&
 | |
|                inside == TRUE &&
 | |
|                mapvals.lightsource.type != NO_LIGHT)
 | |
|         {
 | |
|           /* Compute shading at this point */
 | |
|           /* ============================= */
 | |
| 
 | |
|           color = phong_shade (&spos1,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &normal,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   if (mapvals.transparent_background == FALSE && color.a < 1.0)
 | |
|     {
 | |
|       pika_rgb_composite (&color, &background,
 | |
|                           PIKA_RGB_COMPOSITE_BEHIND);
 | |
|     }
 | |
| 
 | |
|   return color;
 | |
| }
 | |
| 
 | |
| /***************************************************/
 | |
| /* Transform the corners of the bounding box to 2D */
 | |
| /***************************************************/
 | |
| 
 | |
| void
 | |
| compute_bounding_box (void)
 | |
| {
 | |
|   PikaVector3  p1, p2;
 | |
|   gdouble      t;
 | |
|   PikaVector3  dir;
 | |
| 
 | |
|   p1 = mapvals.position;
 | |
|   p1.x -= (mapvals.radius + 0.01);
 | |
|   p1.y -= (mapvals.radius + 0.01);
 | |
| 
 | |
|   p2 = mapvals.position;
 | |
|   p2.x += (mapvals.radius + 0.01);
 | |
|   p2.y += (mapvals.radius + 0.01);
 | |
| 
 | |
|   pika_vector3_sub (&dir, &p1, &mapvals.viewpoint);
 | |
|   pika_vector3_normalize (&dir);
 | |
| 
 | |
|   if (dir.z != 0.0)
 | |
|     {
 | |
|       t = (-1.0 * mapvals.viewpoint.z) / dir.z;
 | |
|       p1.x = (mapvals.viewpoint.x + t * dir.x);
 | |
|       p1.y = (mapvals.viewpoint.y + t * dir.y);
 | |
|     }
 | |
| 
 | |
|   pika_vector3_sub (&dir, &p2, &mapvals.viewpoint);
 | |
|   pika_vector3_normalize (&dir);
 | |
| 
 | |
|   if (dir.z != 0.0)
 | |
|     {
 | |
|       t = (-1.0 * mapvals.viewpoint.z) / dir.z;
 | |
|       p2.x = (mapvals.viewpoint.x + t * dir.x);
 | |
|       p2.y = (mapvals.viewpoint.y + t * dir.y);
 | |
|     }
 | |
| 
 | |
|   bx1 = p1.x;
 | |
|   by1 = p1.y;
 | |
|   bx2 = p2.x;
 | |
|   by2 = p2.y;
 | |
| }
 | |
| 
 | |
| /* These two were taken from the Mesa source. Mesa is written   */
 | |
| /* and is (C) by Brian Paul. vecmulmat() performs a post-mul by */
 | |
| /* a 4x4 matrix to a 1x4(3) vector. rotmat() creates a matrix   */
 | |
| /* that by post-mul will rotate a 1x4(3) vector the given angle */
 | |
| /* about the given axis.                                        */
 | |
| /* ============================================================ */
 | |
| 
 | |
| void
 | |
| vecmulmat (PikaVector3 *u,
 | |
|            PikaVector3 *v,
 | |
|            gfloat       m[16])
 | |
| {
 | |
|   gfloat v0=v->x, v1=v->y, v2=v->z;
 | |
| #define M(row,col)  m[col*4+row]
 | |
|   u->x = v0 * M(0,0) + v1 * M(1,0) + v2 * M(2,0) + M(3,0);
 | |
|   u->y = v0 * M(0,1) + v1 * M(1,1) + v2 * M(2,1) + M(3,1);
 | |
|   u->z = v0 * M(0,2) + v1 * M(1,2) + v2 * M(2,2) + M(3,2);
 | |
| #undef M
 | |
| }
 | |
| 
 | |
| void
 | |
| rotatemat (gfloat       angle,
 | |
|            PikaVector3 *v,
 | |
|            gfloat       m[16])
 | |
| {
 | |
|   /* This function contributed by Erich Boleyn (erich@uruk.org) */
 | |
|   gfloat mag, s, c;
 | |
|   gfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
 | |
|   gfloat IdentityMat[16];
 | |
|   gint   cnt;
 | |
| 
 | |
|   s = sin (angle * (G_PI / 180.0));
 | |
|   c = cos (angle * (G_PI / 180.0));
 | |
| 
 | |
|   mag = sqrt (v->x*v->x + v->y*v->y + v->z*v->z);
 | |
| 
 | |
|   if (mag == 0.0)
 | |
|     {
 | |
|       /* generate an identity matrix and return */
 | |
| 
 | |
|       for (cnt = 0; cnt < 16; cnt++)
 | |
|         IdentityMat[cnt] = 0.0;
 | |
| 
 | |
|       IdentityMat[0]  = 1.0;
 | |
|       IdentityMat[5]  = 1.0;
 | |
|       IdentityMat[10] = 1.0;
 | |
|       IdentityMat[15] = 1.0;
 | |
| 
 | |
|       memcpy (m, IdentityMat, sizeof (gfloat) * 16);
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|   v->x /= mag;
 | |
|   v->y /= mag;
 | |
|   v->z /= mag;
 | |
| 
 | |
| #define M(row,col)  m[col*4+row]
 | |
| 
 | |
|   xx = v->x * v->x;
 | |
|   yy = v->y * v->y;
 | |
|   zz = v->z * v->z;
 | |
|   xy = v->x * v->y;
 | |
|   yz = v->y * v->z;
 | |
|   zx = v->z * v->x;
 | |
|   xs = v->x * s;
 | |
|   ys = v->y * s;
 | |
|   zs = v->z * s;
 | |
|   one_c = 1.0F - c;
 | |
| 
 | |
|   M(0,0) = (one_c * xx) + c;
 | |
|   M(0,1) = (one_c * xy) - zs;
 | |
|   M(0,2) = (one_c * zx) + ys;
 | |
|   M(0,3) = 0.0F;
 | |
| 
 | |
|   M(1,0) = (one_c * xy) + zs;
 | |
|   M(1,1) = (one_c * yy) + c;
 | |
|   M(1,2) = (one_c * yz) - xs;
 | |
|   M(1,3) = 0.0F;
 | |
| 
 | |
|   M(2,0) = (one_c * zx) - ys;
 | |
|   M(2,1) = (one_c * yz) + xs;
 | |
|   M(2,2) = (one_c * zz) + c;
 | |
|   M(2,3) = 0.0F;
 | |
| 
 | |
|   M(3,0) = 0.0F;
 | |
|   M(3,1) = 0.0F;
 | |
|   M(3,2) = 0.0F;
 | |
|   M(3,3) = 1.0F;
 | |
| 
 | |
| #undef M
 | |
| }
 | |
| 
 | |
| /* Transpose the matrix m. If m is orthogonal (like a rotation matrix), */
 | |
| /* this is equal to the inverse of the matrix.                          */
 | |
| /* ==================================================================== */
 | |
| 
 | |
| void
 | |
| transpose_mat (gfloat m[16])
 | |
| {
 | |
|   gint    i, j;
 | |
|   gfloat  t;
 | |
| 
 | |
|   for (i = 0; i < 4; i++)
 | |
|     {
 | |
|       for (j = 0; j < i; j++)
 | |
|         {
 | |
|           t = m[j*4+i];
 | |
|           m[j*4+i] = m[i*4+j];
 | |
|           m[i*4+j] = t;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Compute the matrix product c=a*b */
 | |
| /* ================================ */
 | |
| 
 | |
| void
 | |
| matmul (gfloat a[16],
 | |
|         gfloat b[16],
 | |
|         gfloat c[16])
 | |
| {
 | |
|   gint   i, j, k;
 | |
|   gfloat value;
 | |
| 
 | |
| #define A(row,col)  a[col*4+row]
 | |
| #define B(row,col)  b[col*4+row]
 | |
| #define C(row,col)  c[col*4+row]
 | |
| 
 | |
|   for (i = 0; i < 4; i++)
 | |
|     {
 | |
|       for (j = 0; j < 4; j++)
 | |
|         {
 | |
|           value = 0.0;
 | |
| 
 | |
|           for (k = 0; k < 4; k++)
 | |
|             value += A(i,k) * B(k,j);
 | |
| 
 | |
|           C(i,j) = value;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #undef A
 | |
| #undef B
 | |
| #undef C
 | |
| }
 | |
| 
 | |
| void
 | |
| ident_mat (gfloat m[16])
 | |
| {
 | |
|   gint  i, j;
 | |
| 
 | |
| #define M(row,col)  m[col*4+row]
 | |
| 
 | |
|   for (i = 0; i < 4; i++)
 | |
|     {
 | |
|       for (j = 0; j < 4; j++)
 | |
|         {
 | |
|           if (i == j)
 | |
|             M(i,j) = 1.0;
 | |
|           else
 | |
|             M(i,j) = 0.0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #undef M
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| intersect_rect (gdouble            u,
 | |
|                 gdouble            v,
 | |
|                 gdouble            w,
 | |
|                 PikaVector3        viewp,
 | |
|                 PikaVector3        dir,
 | |
|                 FaceIntersectInfo *face_info)
 | |
| {
 | |
|   gboolean result = FALSE;
 | |
|   gdouble  u2, v2;
 | |
| 
 | |
|   if (dir.z!=0.0)
 | |
|     {
 | |
|       u2 = u / 2.0;
 | |
|       v2 = v / 2.0;
 | |
| 
 | |
|       face_info->t = (w-viewp.z) / dir.z;
 | |
|       face_info->s.x = viewp.x + face_info->t * dir.x;
 | |
|       face_info->s.y = viewp.y + face_info->t * dir.y;
 | |
|       face_info->s.z = w;
 | |
| 
 | |
|       if (face_info->s.x >= -u2 && face_info->s.x <= u2 &&
 | |
|           face_info->s.y >= -v2 && face_info->s.y <= v2)
 | |
|         {
 | |
|           face_info->u = (face_info->s.x + u2) / u;
 | |
|           face_info->v = (face_info->s.y + v2) / v;
 | |
|           result = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| intersect_box (PikaVector3        scale,
 | |
|                PikaVector3        viewp,
 | |
|                PikaVector3        dir,
 | |
|                FaceIntersectInfo *face_intersect)
 | |
| {
 | |
|   PikaVector3        v, d, tmp, axis[3];
 | |
|   FaceIntersectInfo  face_tmp;
 | |
|   gboolean           result = FALSE;
 | |
|   gfloat             m[16];
 | |
|   gint               i = 0;
 | |
| 
 | |
|   pika_vector3_set (&axis[0], 1.0, 0.0, 0.0);
 | |
|   pika_vector3_set (&axis[1], 0.0, 1.0, 0.0);
 | |
|   pika_vector3_set (&axis[2], 0.0, 0.0, 1.0);
 | |
| 
 | |
|   /* Front side */
 | |
|   /* ========== */
 | |
| 
 | |
|   if (intersect_rect (scale.x, scale.y, scale.z / 2.0,
 | |
|                       viewp, dir, &face_intersect[i]) == TRUE)
 | |
|     {
 | |
|       face_intersect[i].face = 0;
 | |
|       pika_vector3_set (&face_intersect[i++].n, 0.0, 0.0, 1.0);
 | |
|       result = TRUE;
 | |
|     }
 | |
| 
 | |
|   /* Back side */
 | |
|   /* ========= */
 | |
| 
 | |
|   if (intersect_rect (scale.x, scale.y, -scale.z / 2.0,
 | |
|                       viewp, dir, &face_intersect[i]) == TRUE)
 | |
|     {
 | |
|       face_intersect[i].face = 1;
 | |
|       face_intersect[i].u = 1.0 - face_intersect[i].u;
 | |
|       pika_vector3_set (&face_intersect[i++].n, 0.0, 0.0, -1.0);
 | |
|       result = TRUE;
 | |
|     }
 | |
| 
 | |
|   /* Check if we've found the two possible intersection points */
 | |
|   /* ========================================================= */
 | |
| 
 | |
|   if (i < 2)
 | |
|     {
 | |
|       /* Top: Rotate viewpoint and direction into rectangle's local coordinate system */
 | |
|       /* ============================================================================ */
 | |
| 
 | |
|       rotatemat (90, &axis[0], m);
 | |
|       vecmulmat (&v, &viewp, m);
 | |
|       vecmulmat (&d, &dir, m);
 | |
| 
 | |
|       if (intersect_rect (scale.x, scale.z, scale.y / 2.0,
 | |
|                           v, d, &face_intersect[i]) == TRUE)
 | |
|         {
 | |
|           face_intersect[i].face = 2;
 | |
| 
 | |
|           transpose_mat (m);
 | |
|           vecmulmat(&tmp, &face_intersect[i].s, m);
 | |
|           face_intersect[i].s = tmp;
 | |
| 
 | |
|           pika_vector3_set (&face_intersect[i++].n, 0.0, -1.0, 0.0);
 | |
|           result = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   /* Check if we've found the two possible intersection points */
 | |
|   /* ========================================================= */
 | |
| 
 | |
|   if (i < 2)
 | |
|     {
 | |
|       /* Bottom: Rotate viewpoint and direction into rectangle's local coordinate system */
 | |
|       /* =============================================================================== */
 | |
| 
 | |
|       rotatemat (90, &axis[0], m);
 | |
|       vecmulmat (&v, &viewp, m);
 | |
|       vecmulmat (&d, &dir, m);
 | |
| 
 | |
|       if (intersect_rect (scale.x, scale.z, -scale.y / 2.0,
 | |
|                           v, d, &face_intersect[i]) == TRUE)
 | |
|         {
 | |
|           face_intersect[i].face = 3;
 | |
| 
 | |
|           transpose_mat (m);
 | |
| 
 | |
|           vecmulmat (&tmp, &face_intersect[i].s, m);
 | |
|           face_intersect[i].s = tmp;
 | |
| 
 | |
|           face_intersect[i].v = 1.0 - face_intersect[i].v;
 | |
| 
 | |
|           pika_vector3_set (&face_intersect[i++].n, 0.0, 1.0, 0.0);
 | |
| 
 | |
|           result = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   /* Check if we've found the two possible intersection points */
 | |
|   /* ========================================================= */
 | |
| 
 | |
|   if (i < 2)
 | |
|     {
 | |
|       /* Left side: Rotate viewpoint and direction into rectangle's local coordinate system */
 | |
|       /* ================================================================================== */
 | |
| 
 | |
|       rotatemat (90, &axis[1], m);
 | |
|       vecmulmat (&v, &viewp, m);
 | |
|       vecmulmat (&d, &dir, m);
 | |
| 
 | |
|       if (intersect_rect (scale.z, scale.y, scale.x / 2.0,
 | |
|                           v, d, &face_intersect[i]) == TRUE)
 | |
|         {
 | |
|           face_intersect[i].face = 4;
 | |
| 
 | |
|           transpose_mat (m);
 | |
|           vecmulmat (&tmp, &face_intersect[i].s, m);
 | |
|           face_intersect[i].s = tmp;
 | |
| 
 | |
|           pika_vector3_set (&face_intersect[i++].n, 1.0, 0.0, 0.0);
 | |
|           result = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   /* Check if we've found the two possible intersection points */
 | |
|   /* ========================================================= */
 | |
| 
 | |
|   if (i < 2)
 | |
|     {
 | |
|       /* Right side: Rotate viewpoint and direction into rectangle's local coordinate system */
 | |
|       /* =================================================================================== */
 | |
| 
 | |
|       rotatemat (90, &axis[1], m);
 | |
|       vecmulmat (&v, &viewp, m);
 | |
|       vecmulmat (&d, &dir, m);
 | |
| 
 | |
|       if (intersect_rect (scale.z, scale.y, -scale.x / 2.0,
 | |
|                           v, d, &face_intersect[i]) == TRUE)
 | |
|         {
 | |
|           face_intersect[i].face = 5;
 | |
| 
 | |
|           transpose_mat (m);
 | |
|           vecmulmat (&tmp, &face_intersect[i].s, m);
 | |
| 
 | |
|           face_intersect[i].u = 1.0 - face_intersect[i].u;
 | |
| 
 | |
|           pika_vector3_set (&face_intersect[i++].n, -1.0, 0.0, 0.0);
 | |
|           result = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   /* Sort intersection points */
 | |
|   /* ======================== */
 | |
| 
 | |
|   if (face_intersect[0].t > face_intersect[1].t)
 | |
|     {
 | |
|       face_tmp = face_intersect[0];
 | |
|       face_intersect[0] = face_intersect[1];
 | |
|       face_intersect[1] = face_tmp;
 | |
|     }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| PikaRGB
 | |
| get_ray_color_box (PikaVector3 *pos)
 | |
| {
 | |
|   PikaVector3        lvp, ldir, vp, p, dir, ns, nn;
 | |
|   PikaRGB             color, color2;
 | |
|   gfloat             m[16];
 | |
|   gint               i;
 | |
|   FaceIntersectInfo  face_intersect[2];
 | |
| 
 | |
|   color = background;
 | |
|   vp = mapvals.viewpoint;
 | |
|   p = *pos;
 | |
| 
 | |
|   /* Translate viewpoint so that the box has its origin */
 | |
|   /* at its lower left corner.                          */
 | |
|   /* ================================================== */
 | |
| 
 | |
|   vp.x = vp.x - mapvals.position.x;
 | |
|   vp.y = vp.y - mapvals.position.y;
 | |
|   vp.z = vp.z - mapvals.position.z;
 | |
| 
 | |
|   p.x = p.x - mapvals.position.x;
 | |
|   p.y = p.y - mapvals.position.y;
 | |
|   p.z = p.z - mapvals.position.z;
 | |
| 
 | |
|   /* Compute direction */
 | |
|   /* ================= */
 | |
| 
 | |
|   pika_vector3_sub (&dir, &p, &vp);
 | |
|   pika_vector3_normalize (&dir);
 | |
| 
 | |
|   /* Compute inverse of rotation matrix and apply it to   */
 | |
|   /* the viewpoint and direction. This transforms the     */
 | |
|   /* observer into the local coordinate system of the box */
 | |
|   /* ==================================================== */
 | |
| 
 | |
|   memcpy (m, rotmat, sizeof (gfloat) * 16);
 | |
| 
 | |
|   transpose_mat (m);
 | |
| 
 | |
|   vecmulmat (&lvp, &vp, m);
 | |
|   vecmulmat (&ldir, &dir, m);
 | |
| 
 | |
|   /* Ok. Now the observer is in the space where the box is located */
 | |
|   /* with its lower left corner at the origin and its axis aligned */
 | |
|   /* to the cartesian basis. Check if the transformed ray hits it. */
 | |
|   /* ============================================================= */
 | |
| 
 | |
|   face_intersect[0].t = 1000000.0;
 | |
|   face_intersect[1].t = 1000000.0;
 | |
| 
 | |
|   if (intersect_box (mapvals.scale, lvp, ldir, face_intersect) == TRUE)
 | |
|     {
 | |
|       /* We've hit the box. Transform the hit points and */
 | |
|       /* normals back into the world coordinate system   */
 | |
|       /* =============================================== */
 | |
| 
 | |
|       for (i = 0; i < 2; i++)
 | |
|         {
 | |
|           vecmulmat (&ns, &face_intersect[i].s, rotmat);
 | |
|           vecmulmat (&nn, &face_intersect[i].n, rotmat);
 | |
| 
 | |
|           ns.x = ns.x + mapvals.position.x;
 | |
|           ns.y = ns.y + mapvals.position.y;
 | |
|           ns.z = ns.z + mapvals.position.z;
 | |
| 
 | |
|           face_intersect[i].s = ns;
 | |
|           face_intersect[i].n = nn;
 | |
|         }
 | |
| 
 | |
|       color = get_box_image_color (face_intersect[0].face,
 | |
|                                    face_intersect[0].u,
 | |
|                                    face_intersect[0].v);
 | |
| 
 | |
|       /* Check for total transparency... */
 | |
|       /* =============================== */
 | |
| 
 | |
|       if (color.a < 1.0)
 | |
|         {
 | |
|           /* Hey, we can see  through here!      */
 | |
|           /* Lets see what's on the other side.. */
 | |
|           /* =================================== */
 | |
| 
 | |
|           color = phong_shade (&face_intersect[0].s,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &face_intersect[0].n,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
| 
 | |
|           color2 = get_box_image_color (face_intersect[1].face,
 | |
|                                         face_intersect[1].u,
 | |
|                                         face_intersect[1].v);
 | |
| 
 | |
|           /* Make the normal point inwards */
 | |
|           /* ============================= */
 | |
| 
 | |
|           pika_vector3_mul (&face_intersect[1].n, -1.0);
 | |
| 
 | |
|           color2 = phong_shade (&face_intersect[1].s,
 | |
|                                 &mapvals.viewpoint,
 | |
|                                 &face_intersect[1].n,
 | |
|                                 &color2,
 | |
|                                 &mapvals.lightsource.color,
 | |
|                                 mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color2);
 | |
| 
 | |
|           if (mapvals.transparent_background == FALSE && color2.a < 1.0)
 | |
|             {
 | |
|               pika_rgb_composite (&color2, &background,
 | |
|                                   PIKA_RGB_COMPOSITE_BEHIND);
 | |
|             }
 | |
| 
 | |
|           /* Compute a mix of the first and second colors */
 | |
|           /* ============================================ */
 | |
| 
 | |
|           pika_rgb_composite (&color, &color2, PIKA_RGB_COMPOSITE_NORMAL);
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|       else if (color.a != 0.0 && mapvals.lightsource.type != NO_LIGHT)
 | |
|         {
 | |
|           color = phong_shade (&face_intersect[0].s,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &face_intersect[0].n,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (mapvals.transparent_background == TRUE)
 | |
|         pika_rgb_set_alpha (&color, 0.0);
 | |
|     }
 | |
| 
 | |
|   return color;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| intersect_circle (PikaVector3        vp,
 | |
|                   PikaVector3        dir,
 | |
|                   gdouble            w,
 | |
|                   FaceIntersectInfo *face_info)
 | |
| {
 | |
|   gboolean result = FALSE;
 | |
|   gdouble  r, d;
 | |
| 
 | |
| #define sqr(a) (a*a)
 | |
| 
 | |
|   if (dir.y != 0.0)
 | |
|     {
 | |
|       face_info->t = (w-vp.y)/dir.y;
 | |
|       face_info->s.x = vp.x + face_info->t*dir.x;
 | |
|       face_info->s.y = w;
 | |
|       face_info->s.z = vp.z + face_info->t*dir.z;
 | |
| 
 | |
|       r = sqrt (sqr (face_info->s.x) + sqr (face_info->s.z));
 | |
| 
 | |
|       if (r <= mapvals.cylinder_radius)
 | |
|         {
 | |
|           d = 2.0 * mapvals.cylinder_radius;
 | |
|           face_info->u = (face_info->s.x + mapvals.cylinder_radius) / d;
 | |
|           face_info->v = (face_info->s.z + mapvals.cylinder_radius) / d;
 | |
|           result = TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #undef sqr
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| intersect_cylinder (PikaVector3        vp,
 | |
|                     PikaVector3        dir,
 | |
|                     FaceIntersectInfo *face_intersect)
 | |
| {
 | |
|   gdouble  a, b, c, d, e, f, tmp, l;
 | |
|   gboolean result = FALSE;
 | |
|   gint     i;
 | |
| 
 | |
| #define sqr(a) (a*a)
 | |
| 
 | |
|   a = sqr (dir.x) + sqr (dir.z);
 | |
|   b = 2.0 * (vp.x * dir.x + vp.z * dir.z);
 | |
|   c = sqr (vp.x) + sqr (vp.z) - sqr (mapvals.cylinder_radius);
 | |
| 
 | |
|   d = sqr (b) - 4.0 * a * c;
 | |
| 
 | |
|   if (d >= 0.0)
 | |
|     {
 | |
|       e = sqrt (d);
 | |
|       f = 2.0 * a;
 | |
| 
 | |
|       if (f != 0.0)
 | |
|         {
 | |
|           result = TRUE;
 | |
| 
 | |
|           face_intersect[0].t = (-b+e)/f;
 | |
|           face_intersect[1].t = (-b-e)/f;
 | |
| 
 | |
|           if (face_intersect[0].t>face_intersect[1].t)
 | |
|             {
 | |
|               tmp = face_intersect[0].t;
 | |
|               face_intersect[0].t = face_intersect[1].t;
 | |
|               face_intersect[1].t = tmp;
 | |
|             }
 | |
| 
 | |
|           for (i = 0; i < 2; i++)
 | |
|             {
 | |
|               face_intersect[i].s.x = vp.x + face_intersect[i].t * dir.x;
 | |
|               face_intersect[i].s.y = vp.y + face_intersect[i].t * dir.y;
 | |
|               face_intersect[i].s.z = vp.z + face_intersect[i].t * dir.z;
 | |
| 
 | |
|               face_intersect[i].n = face_intersect[i].s;
 | |
|               face_intersect[i].n.y = 0.0;
 | |
|               pika_vector3_normalize(&face_intersect[i].n);
 | |
| 
 | |
|               l = mapvals.cylinder_length/2.0;
 | |
| 
 | |
|               face_intersect[i].u = (atan2(face_intersect[i].s.x,face_intersect[i].s.z)+G_PI)/(2.0*G_PI);
 | |
|               face_intersect[i].v = (face_intersect[i].s.y+l)/mapvals.cylinder_length;
 | |
| 
 | |
|               /* Mark hitpoint as on the cylinder hull */
 | |
|               /* ===================================== */
 | |
| 
 | |
|               face_intersect[i].face = 0;
 | |
| 
 | |
|               /* Check if we're completely off the cylinder axis */
 | |
|               /* =============================================== */
 | |
| 
 | |
|               if (face_intersect[i].s.y>l || face_intersect[i].s.y<-l)
 | |
|                 {
 | |
|                   /* Check if we've hit a cap */
 | |
|                   /* ======================== */
 | |
| 
 | |
|                   if (face_intersect[i].s.y>l)
 | |
|                     {
 | |
|                       if (intersect_circle(vp,dir,l,&face_intersect[i])==FALSE)
 | |
|                         result = FALSE;
 | |
|                       else
 | |
|                         {
 | |
|                           face_intersect[i].face = 2;
 | |
|                           face_intersect[i].v = 1 - face_intersect[i].v;
 | |
|                           pika_vector3_set(&face_intersect[i].n, 0.0, 1.0, 0.0);
 | |
|                         }
 | |
|                     }
 | |
|                   else
 | |
|                     {
 | |
|                       if (intersect_circle(vp,dir,-l,&face_intersect[i])==FALSE)
 | |
|                         result = FALSE;
 | |
|                       else
 | |
|                         {
 | |
|                           face_intersect[i].face = 1;
 | |
|                           pika_vector3_set(&face_intersect[i].n, 0.0, -1.0, 0.0);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #undef sqr
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| static PikaRGB
 | |
| get_cylinder_color (gint    face,
 | |
|                     gdouble u,
 | |
|                     gdouble v)
 | |
| {
 | |
|   PikaRGB  color;
 | |
|   gint    inside;
 | |
| 
 | |
|   if (face == 0)
 | |
|     color = get_image_color (u, v, &inside);
 | |
|   else
 | |
|     color = get_cylinder_image_color (face - 1, u, v);
 | |
| 
 | |
|   return color;
 | |
| }
 | |
| 
 | |
| PikaRGB
 | |
| get_ray_color_cylinder (PikaVector3 *pos)
 | |
| {
 | |
|   PikaVector3       lvp, ldir, vp, p, dir, ns, nn;
 | |
|   PikaRGB            color, color2;
 | |
|   gfloat            m[16];
 | |
|   gint              i;
 | |
|   FaceIntersectInfo face_intersect[2];
 | |
| 
 | |
|   color = background;
 | |
|   vp = mapvals.viewpoint;
 | |
|   p = *pos;
 | |
| 
 | |
|   vp.x = vp.x - mapvals.position.x;
 | |
|   vp.y = vp.y - mapvals.position.y;
 | |
|   vp.z = vp.z - mapvals.position.z;
 | |
| 
 | |
|   p.x = p.x - mapvals.position.x;
 | |
|   p.y = p.y - mapvals.position.y;
 | |
|   p.z = p.z - mapvals.position.z;
 | |
| 
 | |
|   /* Compute direction */
 | |
|   /* ================= */
 | |
| 
 | |
|   pika_vector3_sub (&dir, &p, &vp);
 | |
|   pika_vector3_normalize (&dir);
 | |
| 
 | |
|   /* Compute inverse of rotation matrix and apply it to   */
 | |
|   /* the viewpoint and direction. This transforms the     */
 | |
|   /* observer into the local coordinate system of the box */
 | |
|   /* ==================================================== */
 | |
| 
 | |
|   memcpy (m, rotmat, sizeof (gfloat) * 16);
 | |
| 
 | |
|   transpose_mat (m);
 | |
| 
 | |
|   vecmulmat (&lvp, &vp, m);
 | |
|   vecmulmat (&ldir, &dir, m);
 | |
| 
 | |
|   if (intersect_cylinder (lvp, ldir, face_intersect) == TRUE)
 | |
|     {
 | |
|       /* We've hit the cylinder. Transform the hit points and */
 | |
|       /* normals back into the world coordinate system        */
 | |
|       /* ==================================================== */
 | |
| 
 | |
|       for (i = 0; i < 2; i++)
 | |
|         {
 | |
|           vecmulmat (&ns, &face_intersect[i].s, rotmat);
 | |
|           vecmulmat (&nn, &face_intersect[i].n, rotmat);
 | |
| 
 | |
|           ns.x = ns.x + mapvals.position.x;
 | |
|           ns.y = ns.y + mapvals.position.y;
 | |
|           ns.z = ns.z + mapvals.position.z;
 | |
| 
 | |
|           face_intersect[i].s = ns;
 | |
|           face_intersect[i].n = nn;
 | |
|         }
 | |
| 
 | |
|       color = get_cylinder_color (face_intersect[0].face,
 | |
|                                   face_intersect[0].u,
 | |
|                                   face_intersect[0].v);
 | |
| 
 | |
|       /* Check for transparency... */
 | |
|       /* ========================= */
 | |
| 
 | |
|       if (color.a < 1.0)
 | |
|         {
 | |
|           /* Hey, we can see  through here!      */
 | |
|           /* Lets see what's on the other side.. */
 | |
|           /* =================================== */
 | |
| 
 | |
|           color = phong_shade (&face_intersect[0].s,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &face_intersect[0].n,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
| 
 | |
|           color2 = get_cylinder_color (face_intersect[1].face,
 | |
|                                        face_intersect[1].u,
 | |
|                                        face_intersect[1].v);
 | |
| 
 | |
|           /* Make the normal point inwards */
 | |
|           /* ============================= */
 | |
| 
 | |
|           pika_vector3_mul (&face_intersect[1].n, -1.0);
 | |
| 
 | |
|           color2 = phong_shade (&face_intersect[1].s,
 | |
|                                 &mapvals.viewpoint,
 | |
|                                 &face_intersect[1].n,
 | |
|                                 &color2,
 | |
|                                 &mapvals.lightsource.color,
 | |
|                                 mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color2);
 | |
| 
 | |
|           if (mapvals.transparent_background == FALSE && color2.a < 1.0)
 | |
|             {
 | |
|               pika_rgb_composite (&color2, &background,
 | |
|                                   PIKA_RGB_COMPOSITE_BEHIND);
 | |
|             }
 | |
| 
 | |
|           /* Compute a mix of the first and second colors */
 | |
|           /* ============================================ */
 | |
| 
 | |
|           pika_rgb_composite (&color, &color2, PIKA_RGB_COMPOSITE_NORMAL);
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|       else if (color.a != 0.0 && mapvals.lightsource.type != NO_LIGHT)
 | |
|         {
 | |
|           color = phong_shade (&face_intersect[0].s,
 | |
|                                &mapvals.viewpoint,
 | |
|                                &face_intersect[0].n,
 | |
|                                &color,
 | |
|                                &mapvals.lightsource.color,
 | |
|                                mapvals.lightsource.type);
 | |
| 
 | |
|           pika_rgb_clamp (&color);
 | |
|         }
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (mapvals.transparent_background == TRUE)
 | |
|         pika_rgb_set_alpha (&color, 0.0);
 | |
|     }
 | |
| 
 | |
|   return color;
 | |
| }
 |