home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * hfield.c
- *
- * This file implements the height field shape primitive. The shape is
- * implemented as a collection of triangles which are calculated as
- * needed. The basic intersection routine first computes the rays
- * intersection with the box marking the limits of the shape, then
- * follows the line from one intersection point to the other, testing the
- * two triangles which form the pixel for an intersection with the ray at
- * each step.
- * height field added by Doug Muir
- * with lots of advice and support from David Buck
- * and Drew Wells.
- *
- * from Persistence of Vision Raytracer
- * Copyright 1993 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
-
- #define sign(x) (((x) > 0.0) ? 1: (((x) < 0.0) ? -1: 0))
-
- #ifndef min_value
- #define min_value(x,y) ((x) > (y) ? (y) : (x))
- #endif
- #ifndef max_value
- #define max_value(x,y) ((x) < (y) ? (y) : (x))
- #endif
-
- METHODS Height_Field_Methods =
- {
- All_HeightFld_Intersections,
- Inside_HeightFld, HeightFld_Normal,
- Copy_HeightFld, Translate_HeightFld, Rotate_HeightFld,
- Scale_HeightFld, Transform_HeightFld, Invert_HeightFld,Destroy_HeightFld
- };
-
- METHODS Csg_Height_Field_Methods =
- {
- All_Csg_HeightFld_Intersections,
- Inside_HeightFld, HeightFld_Normal,
- Copy_HeightFld,
- Translate_HeightFld, Rotate_HeightFld,
- Scale_HeightFld, Transform_HeightFld, Invert_HeightFld,Destroy_HeightFld
- };
-
- extern long Ray_Ht_Field_Tests, Ray_Ht_Field_Tests_Succeeded;
- extern long Ray_Ht_Field_Box_Tests, Ray_HField_Box_Tests_Succeeded;
- extern int Options;
-
- int isdx, isdz, X_Dom;
- DBL Gdx, Gdy, Gdz, Block_Size, Inv_Blk_Size;
- DBL Myx, Mxz, Mzx, Myz;
- ISTACK *Hf_Stack;
- RAY *RRay;
- DBL mindist, maxdist;
-
- #define Get_Height(x, z, H_Field) ((DBL)(H_Field)->Map[(z)][(x)])
-
- static DBL Normalize PARAMS(( VECTOR *A, VECTOR *B ));
- static DBL stretch PARAMS((DBL x));
- static int Intersect_Csg_Sub_Block PARAMS((HF_BLOCK *Block, RAY *Ray,
- HEIGHT_FIELD *H_Field, VECTOR *start, VECTOR *end));
- static int Intersect_Csg_Hf_Node PARAMS((RAY *Ray, HEIGHT_FIELD *H_Field,
- VECTOR *start, VECTOR *end));
- static DBL Normalize PARAMS(( VECTOR *A, VECTOR *B ));
- static int add_single_normal PARAMS((HF_val **data, int xsize, int zsize,
- int x0, int z0,int x1, int z1,int x2, int z2,VECTOR *N));
- static void smooth_height_field PARAMS((HEIGHT_FIELD *hf, int xsize, int zsize));
-
- static DBL
- Normalize(A, B)
- VECTOR *A, *B;
- {
- DBL VTemp = sqrt(B->x * B->x + B->y * B->y + B->z * B->z);
- if (fabs(VTemp) > EPSILON)
- {
- A->x = B->x / VTemp;
- A->y = B->y / VTemp;
- A->z = B->z / VTemp;
- }
- else
- {
- A->x = 0.0;
- A->y = 1.0;
- A->z = 0.0;
- }
- return VTemp;
- }
-
- int Intersect_Pixel(x, z, Ray, H_Field, height1, height2)
- int x;
- int z;
- RAY *Ray;
- HEIGHT_FIELD *H_Field;
- DBL height1;
- DBL height2;
- {
- VECTOR T1V1,T1V2,T1V3,T2V1,T2V2,T2V3,Local_Normal,N1;
- DBL pos1,pos2,dot,depth1,depth2,s,t,y1,y2,y3,y4;
- DBL max_height, min_height;
- int Found = FALSE;
-
- y1 = Get_Height(x,z,H_Field);
- y2 = Get_Height(x+1,z,H_Field);
- y3 = Get_Height(x,z+1,H_Field);
- y4 = Get_Height(x+1,z+1,H_Field);
-
- Make_Vector(&T1V1,(DBL)x,y1,(DBL)z);
- Make_Vector(&T1V2,1.0,y2-y1,0.0);
- Make_Vector(&T1V3,0.0,y3-y1,1.0);
- Make_Vector(&T2V1,(DBL)(x+1),y4,(DBL)(z+1));
- Make_Vector(&T2V2,-1.0,y3-y4,0.0);
- Make_Vector(&T2V3,0.0,y2-y4,-1.0);
-
- /*
- * first, we check to see if it is even possible for the ray to
- * intersect the triangle.
- */
-
- max_height = max_value(y1,max_value(y2,y3));
- min_height = min_value(y1,min_value(y2,y3));
- if((max_height >= height1) && (min_height <= height2))
- {
- VCross(Local_Normal,T1V3,T1V2);
- VDot(dot,Local_Normal,Ray->Direction);
-
- if((dot > EPSILON) || (dot < -EPSILON))
- {
- VDot(pos1,Local_Normal,T1V1);
- VDot(pos2,Local_Normal,Ray->Initial);
-
- pos1 -= pos2;
-
- depth1 = pos1 / dot;
-
- if((depth1 >= mindist) && (depth1 <= maxdist))
- {
- s = Ray->Initial.x+(depth1*Ray->Direction.x)-(DBL)x;
- t = Ray->Initial.z+(depth1*Ray->Direction.z)-(DBL)z;
-
- if((s>=-0.0001) && (t>=-0.0001) && ((s+t)<=1.0001))
- {
- if (!H_Field->Smoothed)
- {
- N1 = Local_Normal;
- if (H_Field->cache_pos < HF_CACHE_SIZE)
- {
- H_Field->Normal_Vector[H_Field->cache_pos].normal = N1;
- H_Field->Normal_Vector[H_Field->cache_pos].x = x + s;
- H_Field->Normal_Vector[H_Field->cache_pos].z = z + t;
- H_Field->cache_pos += 1;
- }
- }
-
- VScale (T1V1, RRay -> Direction, depth1);
- VAddEq (T1V1, RRay -> Initial);
- if (Point_In_Clip (&T1V1, H_Field->Clip))
- {
- push_entry(depth1,T1V1,(OBJECT *)H_Field,Hf_Stack);
- Found = TRUE;
- Ray_Ht_Field_Tests_Succeeded++;
- }
- }
- }
- }
- }
-
- /*
- * first, we check to see if it is even possible for the ray to
- * intersect the triangle.
- Rewritten to get around Code Builder FP stack problem.
- Original code:
- if((max_value(y4,max_value(y2,y3)) >= height1) &&
- (min_value(y4,min_value(y2,y3)) <= height2)) */
-
- max_height = max_value(y4,max_value(y2,y3));
- min_height = min_value(y4,min_value(y2,y3));
- if((max_height >= height1) && (min_height <= height2))
- {
- VCross(Local_Normal,T2V3,T2V2);
- VDot(dot,Local_Normal,Ray->Direction);
-
- if((dot > EPSILON) || (dot < -EPSILON))
- {
- VDot(pos1,Local_Normal,T2V1);
-
- VDot(pos2,Local_Normal,Ray->Initial);
- pos1 -= pos2;
-
- depth2 = pos1 / dot;
-
- if((depth2 >=mindist) && (depth2 <=maxdist))
- {
- s = Ray->Initial.x+(depth2*Ray->Direction.x)-(DBL)x;
- t = Ray->Initial.z+(depth2*Ray->Direction.z)-(DBL)z;
-
- if((s<=1.0001) && (t<=1.0001) && ((s+t)>0.9999))
- {
- if (!H_Field->Smoothed)
- {
- N1 = Local_Normal;
- if (H_Field->cache_pos < HF_CACHE_SIZE)
- {
- H_Field->Normal_Vector[H_Field->cache_pos].normal = N1;
- H_Field->Normal_Vector[H_Field->cache_pos].x = x + s;
- H_Field->Normal_Vector[H_Field->cache_pos].z = z + t;
- H_Field->cache_pos += 1;
- }
- }
-
- VScale (T1V1, RRay -> Direction, depth2);
- VAddEq (T1V1, RRay -> Initial);
- if (Point_In_Clip (&T1V1, H_Field->Clip))
- {
- push_entry(depth2,T1V1,(OBJECT *)H_Field,Hf_Stack);
- Found = TRUE;
- Ray_Ht_Field_Tests_Succeeded++;
- }
- }
- }
- }
- }
-
- return(Found);
- }
-
- int Intersect_Sub_Block(Block, Ray, H_Field, start, end)
- HF_BLOCK *Block;
- RAY *Ray;
- HEIGHT_FIELD *H_Field;
- VECTOR *start, *end;
- {
- DBL y1, y2;
- DBL sx, sy, sz, ex, ez, f, tx, tz;
- int ix, iz, length, i;
-
- if(min_value(start->y,end->y) > (DBL)Block->max_y)
- return(FALSE);
-
- if(max_value(start->y,end->y) < (DBL)Block->min_y)
- return(FALSE);
-
- sx = start->x;
- ex = end->x;
- sz = start->z;
- ez = end->z;
- sy = start->y;
-
- if(X_Dom)
- {
- if(isdx >= 0)
- {
- f = floor(sx) - sx;
- sx = floor(sx);
- sy += Myx * f;
- sz += Mzx * f;
- ex = ceil(ex) - 1.0;
- ix = (int)sx;
- }
- else
- {
- f = ceil(sx) - sx;
- sx = ceil(sx) - 1.0;
- sy += Myx * f;
- sz += Mzx * f;
- ex = floor(ex);
- ix = (int)sx;
- }
-
- length = (int)abs((int)ex - (int)sx);
-
- if (isdz >= 0)
- {
- tz = floor(start->z) + 1.0;
- iz = (int)start->z;
- f = sz - tz;
- }
- else
- {
- tz = ceil(start->z) - 1.0;
- iz = (int)tz;
- f = tz - sz;
- }
-
- if(Gdy >= 0.0)
- {
- y1 = sy;
- y2 = sy + Gdy;
- }
- else
- {
- y1 = sy + Gdy;
- y2 = sy;
- }
-
- for(i=0;i<=length;i++)
- {
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- return(TRUE);
- f += Gdz;
- if(f>0.0)
- {
- iz += isdz;
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- return(TRUE);
- f -= 1.0;
- }
- ix += isdx;
- y1 += Gdy;
- y2 += Gdy;
- }
- }
- else
- {
- if(isdz >= 0)
- {
- f = floor(sz) - sz;
- sz = floor(sz);
- sy += Myz * f;
- sx += Mxz * f;
- ez = ceil(ez) - 1.0;
- iz = (int)sz;
- }
- else
- {
- f = ceil(sz) - sz;
- sz = ceil(sz) - 1.0;
- sy += Myz * f;
- sx += Mxz * f;
- ez = floor(ez);
- iz = (int)sz;
- }
-
- length = (int)abs((int)ez - (int)sz);
-
- if (isdx >= 0)
- {
- tx = floor(start->x) + 1.0;
- ix = (int)start->x;
- f = sx - tx;
- }
- else
- {
- tx = ceil(start->x) - 1.0;
- ix = (int)tx;
- f = tx - sx;
- }
-
- if(Gdy >= 0.0)
- {
- y1 = sy;
- y2 = sy + Gdy;
- }
- else
- {
- y1 = sy + Gdy;
- y2 = sy;
- }
-
- for(i=0;i<=length;i++)
- {
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- return(TRUE);
- f += Gdx;
- if(f>0.0)
- {
- ix += isdx;
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- return(TRUE);
- f -= 1.0;
- }
- iz += isdz;
- y1 += Gdy;
- y2 += Gdy;
- }
- }
- return (FALSE);
- }
-
- static int Intersect_Csg_Sub_Block(Block, Ray, H_Field, start, end)
- HF_BLOCK *Block;
- RAY *Ray;
- HEIGHT_FIELD *H_Field;
- VECTOR *start, *end;
- {
- DBL y1, y2;
- DBL sx, sy, sz, ex, ez, f, tx, tz;
- int ix, iz, length, i, retval;
-
- if(min_value(start->y,end->y) > (DBL)Block->max_y)
- return(FALSE);
-
- if(max_value(start->y,end->y) < (DBL)Block->min_y)
- return(FALSE);
-
- retval = FALSE;
- sx = start->x;
- ex = end->x;
- sz = start->z;
- ez = end->z;
- sy = start->y;
-
- if(X_Dom)
- {
- if(isdx >= 0)
- {
- f = floor(sx) - sx;
- sx = floor(sx);
- sy += Myx * f;
- sz += Mzx * f;
- ex = ceil(ex) - 1.0;
- ix = (int)sx;
- }
- else
- {
- f = ceil(sx) - sx;
- sx = ceil(sx) - 1.0;
- sy += Myx * f;
- sz += Mzx * f;
- ex = floor(ex);
- ix = (int)sx;
- }
-
- length = (int) abs((int)ex - (int)sx);
-
- if (isdz >= 0)
- {
- tz = floor(start->z) + 1.0;
- iz = (int)start->z;
- f = sz - tz;
- }
- else
- {
- tz = ceil(start->z) - 1.0;
- iz = (int)tz;
- f = tz - sz;
- }
-
- if(Gdy >= 0.0)
- {
- y1 = sy;
- y2 = sy + Gdy;
- }
- else
- {
- y1 = sy + Gdy;
- y2 = sy;
- }
-
- for(i=0;i<=length;i++)
- {
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- retval = TRUE;
- f += Gdz;
- if(f>0.0)
- {
- iz += isdz;
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- retval = TRUE;
- f -= 1.0;
- }
- ix += isdx;
- y1 += Gdy;
- y2 += Gdy;
- }
- }
- else
- {
- if(isdz >= 0)
- {
- f = floor(sz) - sz;
- sz = floor(sz);
- sy += Myz * f;
- sx += Mxz * f;
- ez = ceil(ez) - 1.0;
- iz = (int)sz;
- }
- else
- {
- f = ceil(sz) - sz;
- sz = ceil(sz) - 1.0;
- sy += Myz * f;
- sx += Mxz * f;
- ez = floor(ez);
- iz = (int)sz;
- }
-
- length = (int)abs((int)ez - (int)sz);
-
- if (isdx >= 0)
- {
- tx = floor(start->x) + 1.0;
- ix = (int)start->x;
- f = sx - tx;
- }
- else
- {
- tx = ceil(start->x) - 1.0;
- ix = (int)tx;
- f = tx - sx;
- }
-
- if(Gdy >= 0.0)
- {
- y1 = sy;
- y2 = sy + Gdy;
- }
- else
- {
- y1 = sy + Gdy;
- y2 = sy;
- }
-
- for(i=0;i<=length;i++)
- {
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- retval = TRUE;
- f += Gdx;
- if(f>0.0)
- {
- ix += isdx;
- if(Intersect_Pixel(ix,iz,Ray,H_Field,y1,y2))
- retval = TRUE;
- f -= 1.0;
- }
- iz += isdz;
- y1 += Gdy;
- y2 += Gdy;
- }
- }
- return (retval);
- }
-
- int Intersect_Hf_Node(Ray, H_Field, start, end)
- RAY *Ray;
- HEIGHT_FIELD *H_Field;
- VECTOR *start, *end;
- {
- VECTOR *curr, *next, *temp, temp1, temp2;
- DBL sx, sy, sz, ex, ey, ez, x, y, z;
- DBL tnear, tfar, t, bsx, bsz, bex, bez;
- int ix, iz, x_size, z_size, length, i;
-
- x = sx = start->x;
- y = sy = start->y;
- z = sz = start->z;
- ex = end->x;
- ey = end->y;
- ez = end->z;
-
- bsx = sx * Inv_Blk_Size;
- bsz = sz * Inv_Blk_Size;
- bex = ex * Inv_Blk_Size;
- bez = ez * Inv_Blk_Size;
-
- if (isdx >= 0)
- {
- bsx = floor(bsx);
- bex = ceil(bex) - 1.0;
- }
- else
- {
- bsx = ceil(bsx) - 1.0;
- bex = floor(bex);
- }
-
- if (isdz >= 0)
- {
- bsz = floor(bsz);
- bez = ceil(bez) - 1.0;
- }
- else
- {
- bsz = ceil(bsz) - 1.0;
- bez = floor(bez);
- }
-
- x_size = abs((int)bex - (int)bsx);
- z_size = abs((int)bez - (int)bsz);
-
- length = x_size + z_size;
-
- curr = &temp1;
- next = &temp2;
- Make_Vector(curr, x, y, z);
- t = 0.0;
-
- if(X_Dom)
- {
- if(isdx >= 0)
- {
- ix = (int)floor(sx*Inv_Blk_Size);
- tnear = Block_Size*(ix+1) - sx;
-
- if (isdz >= 0)
- {
- iz = (int)floor(sz*Inv_Blk_Size);
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- }
- else
- {
- iz = (int)ceil(sz*Inv_Blk_Size) - 1;
- tfar = Gdx * (sz - Block_Size*(iz));
- }
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- x = sx + t;
- y = sy + Myx * t;
- z = sz + Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- iz += isdz;
- if (isdz >= 0)
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- else
- tfar = Gdx * (sz - Block_Size*(iz));
- }
- else
- {
- t = tnear;
- x = sx + t;
- y = sy + Myx * t;
- z = sz + Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- ix++;
- tnear = Block_Size*(ix+1) - sx;
- }
- }
- }
- else
- {
- ix = (int)ceil(sx*Inv_Blk_Size) - 1;
- tnear = sx - Block_Size*(ix);
-
- if (isdz >= 0)
- {
- iz = (int)floor(sz*Inv_Blk_Size);
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- }
- else
- {
- iz = (int)ceil(sz*Inv_Blk_Size) - 1;
- tfar = Gdx * (sz - Block_Size*(iz));
- }
-
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- x = sx - t;
- y = sy - Myx * t;
- z = sz - Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- iz += isdz;
- if (isdz >= 0)
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- else
- tfar = Gdx * (sz - Block_Size*(iz));
- }
- else
- {
- t = tnear;
- x = sx - t;
- y = sy - Myx * t;
- z = sz - Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- ix--;
- tnear = sx - Block_Size*(ix);
- }
- }
- }
- }
- else
- {
- if(isdz >= 0)
- {
- iz = (int)floor(sz*Inv_Blk_Size);
- tnear = Block_Size*(iz+1) - sz;
-
- if (isdx >= 0)
- {
- ix = (int)floor(sx*Inv_Blk_Size);
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- }
- else
- {
- ix = (int)ceil(sx*Inv_Blk_Size) - 1;
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- z = sz + t;
- y = sy + Myz * t;
- x = sx + Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- ix += isdx;
- if (isdx >= 0)
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- else
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- else
- {
- t = tnear;
- z = sz + t;
- y = sy + Myz * t;
- x = sx + Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- iz++;
- tnear = Block_Size*(iz+1) - sz;
- }
- }
- }
- else
- {
- iz = (int)ceil(sz*Inv_Blk_Size) - 1;
- tnear = sz - Block_Size*(iz);
-
- if (isdx >= 0)
- {
- ix = (int)floor(sx*Inv_Blk_Size);
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- }
- else
- {
- ix = (int)ceil(sx*Inv_Blk_Size) - 1;
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- z = sz - t;
- y = sy - Myz * t;
- x = sx - Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- ix += isdx;
- if (isdx >= 0)
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- else
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- else
- {
- t = tnear;
- z = sz - t;
- y = sy - Myz * t;
- x = sx - Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- temp = curr;
- curr = next;
- next = temp;
- iz--;
- tnear = sz - Block_Size*iz;
- }
- }
- }
- }
- Make_Vector(next,ex,ey,ez);
- if(isdx >= 0)
- ix = (int)floor(ex*Inv_Blk_Size);
- else
- ix = (int)ceil(ex*Inv_Blk_Size) - 1;
- if(isdz >= 0)
- iz = (int)floor(ez*Inv_Blk_Size);
- else
- iz = (int)ceil(ez*Inv_Blk_Size) - 1;
- if(Intersect_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- return(TRUE);
- return (FALSE);
- }
-
- static int Intersect_Csg_Hf_Node(Ray, H_Field, start, end)
- RAY *Ray;
- HEIGHT_FIELD *H_Field;
- VECTOR *start, *end;
- {
- VECTOR *curr, *next, *temp, temp1, temp2;
- DBL sx, sy, sz, ex, ey, ez, x, y, z;
- DBL tnear, tfar, t, bsx, bsz, bex, bez;
- int ix, iz, x_size, z_size, length, i, retval;
-
- retval = FALSE;
- x = sx = start->x;
- y = sy = start->y;
- z = sz = start->z;
- ex = end->x;
- ey = end->y;
- ez = end->z;
-
- bsx = sx * Inv_Blk_Size;
- bsz = sz * Inv_Blk_Size;
- bex = ex * Inv_Blk_Size;
- bez = ez * Inv_Blk_Size;
-
- if (isdx >= 0)
- {
- bsx = floor(bsx);
- bex = ceil(bex) - 1.0;
- }
- else
- {
- bsx = ceil(bsx) - 1.0;
- bex = floor(bex);
- }
-
- if (isdz >= 0)
- {
- bsz = floor(bsz);
- bez = ceil(bez) - 1.0;
- }
- else
- {
- bsz = ceil(bsz) - 1.0;
- bez = floor(bez);
- }
-
- x_size = abs((int)bex - (int)bsx);
- z_size = abs((int)bez - (int)bsz);
-
- length = x_size + z_size;
-
- curr = &temp1;
- next = &temp2;
- Make_Vector(curr, x, y, z);
- t = 0.0;
-
- if(X_Dom)
- {
- if(isdx >= 0)
- {
- ix = (int)floor(sx*Inv_Blk_Size);
- tnear = Block_Size*(ix+1) - sx;
-
- if (isdz >= 0)
- {
- iz = (int)floor(sz*Inv_Blk_Size);
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- }
- else
- {
- iz = (int)ceil(sz*Inv_Blk_Size) - 1;
- tfar = Gdx * (sz - Block_Size*(iz));
- }
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- x = sx + t;
- y = sy + Myx * t;
- z = sz + Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- iz += isdz;
- if (isdz >= 0)
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- else
- tfar = Gdx * (sz - Block_Size*(iz));
- }
- else
- {
- t = tnear;
- x = sx + t;
- y = sy + Myx * t;
- z = sz + Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- ix++;
- tnear = Block_Size*(ix+1) - sx;
- }
- }
- }
- else
- {
- ix = (int)ceil(sx*Inv_Blk_Size) - 1;
- tnear = sx - Block_Size*(ix);
-
- if (isdz >= 0)
- {
- iz = (int)floor(sz*Inv_Blk_Size);
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- }
- else
- {
- iz = (int)ceil(sz*Inv_Blk_Size) - 1;
- tfar = Gdx * (sz - Block_Size*(iz));
- }
-
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- x = sx - t;
- y = sy - Myx * t;
- z = sz - Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- iz += isdz;
- if (isdz >= 0)
- tfar = Gdx * (Block_Size*(iz+1) - sz);
- else
- tfar = Gdx * (sz - Block_Size*(iz));
- }
- else
- {
- t = tnear;
- x = sx - t;
- y = sy - Myx * t;
- z = sz - Mzx * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- ix--;
- tnear = sx - Block_Size*(ix);
- }
- }
- }
- }
- else
- {
- if(isdz >= 0)
- {
- iz = (int)floor(sz*Inv_Blk_Size);
- tnear = Block_Size*(iz+1) - sz;
-
- if (isdx >= 0)
- {
- ix = (int)floor(sx*Inv_Blk_Size);
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- }
- else
- {
- ix = (int)ceil(sx*Inv_Blk_Size) - 1;
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- z = sz + t;
- y = sy + Myz * t;
- x = sx + Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- ix += isdx;
- if (isdx >= 0)
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- else
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- else
- {
- t = tnear;
- z = sz + t;
- y = sy + Myz * t;
- x = sx + Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- iz++;
- tnear = Block_Size*(iz+1) - sz;
- }
- }
- }
- else
- {
- iz = (int)ceil(sz*Inv_Blk_Size) - 1;
- tnear = sz - Block_Size*(iz);
-
- if (isdx >= 0)
- {
- ix = (int)floor(sx*Inv_Blk_Size);
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- }
- else
- {
- ix = (int)ceil(sx*Inv_Blk_Size) - 1;
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- for (i = 0; i < length; i++)
- {
- if(tfar < tnear)
- {
- t = tfar;
- z = sz - t;
- y = sy - Myz * t;
- x = sx - Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- ix += isdx;
- if (isdx >= 0)
- tfar = Gdz * (Block_Size*(ix+1) - sx);
- else
- tfar = Gdz * (sx - Block_Size*(ix));
- }
- else
- {
- t = tnear;
- z = sz - t;
- y = sy - Myz * t;
- x = sx - Mxz * t;
- Make_Vector(next, x, y, z);
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- temp = curr;
- curr = next;
- next = temp;
- iz--;
- tnear = sz - Block_Size*iz;
- }
- }
- }
- }
- Make_Vector(next,ex,ey,ez);
- if(isdx >= 0)
- ix = (int)floor(ex*Inv_Blk_Size);
- else
- ix = (int)ceil(ex*Inv_Blk_Size) - 1;
- if(isdz >= 0)
- iz = (int)floor(ez*Inv_Blk_Size);
- else
- iz = (int)ceil(ez*Inv_Blk_Size) - 1;
- if(Intersect_Csg_Sub_Block(&(H_Field->Block[ix][iz]),Ray,H_Field,curr,next))
- retval = TRUE;
- return (retval);
- }
-
- static int
- add_single_normal(data, xsize, zsize, x0, z0, x1, z1, x2, z2, N)
- HF_val **data;
- int xsize,zsize,x0,z0,x1,z1,x2,z2;
- VECTOR *N;
- {
- VECTOR v0, v1, v2, t0, t1, Nt;
-
- if (x0 < 0 || z0 < 0 ||
- x1 < 0 || z1 < 0 ||
- x2 < 0 || z2 < 0 ||
- x0 > xsize || z0 > zsize ||
- x1 > xsize || z1 > zsize ||
- x2 > xsize || z2 > zsize)
- {
- return 0;
- }
- else
- {
- Make_Vector(&v0, x0, (DBL)data[z0][x0], z0);
- Make_Vector(&v1, x1, (DBL)data[z1][x1], z1);
- Make_Vector(&v2, x2, (DBL)data[z2][x2], z2);
- VSub(t0, v2, v0);
- VSub(t1, v1, v0);
- VCross(Nt, t0, t1);
- Normalize(&Nt, &Nt);
- if(Nt.y < 0.0)
- {
- VScale(Nt,Nt,-1.0);
- }
- VAdd(*N, *N, Nt);
- return 1;
- }
- }
-
- /* Given a height field that only contains an elevation grid, this
- routine will walk through the data and produce averaged normals
- for all points on the grid. */
- static void
- smooth_height_field(hf, xsize, zsize)
- HEIGHT_FIELD *hf;
- int xsize;
- int zsize;
- {
- int i, j, k;
- VECTOR N;
- HF_val **map = hf->Map;
-
- /* First off, allocate all the memory needed to store the
- normal information */
- hf->Normals = (HF_Normals **)malloc((zsize+1) * sizeof(HF_Normals *));
- if (hf->Normals == NULL)
- {
- fprintf(stderr, "Failed to allocate hf->norm\n");
- exit(1);
- }
- for (i=0; i<=zsize; i++)
- {
- hf->Normals[i] = (HF_Normals *)malloc((xsize+1) * sizeof(HF_Normals));
- if (hf->Normals[i] == NULL)
- {
- fprintf(stderr, "Failed to allocate hf->norm[%d]\n", i);
- exit(1);
- }
- }
-
- /* For now we will do it the hard way - by generating the normals
- individually for each elevation point */
- for (i=0;i<=zsize;i++)
- {
- COOPERATE
- if((i%(int)Block_Size) == 0) fprintf(stderr,".");
- for (j=0;j<=xsize;j++)
- {
- Make_Vector(&N, 0.0, 0.0, 0.0);
- k = 0;
- /*
- k += add_single_normal(map, xsize, zsize, j, i, j+1, i, j, i+1, &N);
- k += add_single_normal(map, xsize, zsize, j+1, i+1, j, i+1, j+1, i, &N);
- k += add_single_normal(map, xsize, zsize, j, i+1, j-1, i+1, j, i, &N);
- k += add_single_normal(map, xsize, zsize, j-1, i, j, i, j-1, i+1, &N);
- k += add_single_normal(map, xsize, zsize, j, i, j-1, i, j, i-1, &N);
- k += add_single_normal(map, xsize, zsize, j-1, i-1, j, i-1, j-1, i, &N);
- k += add_single_normal(map, xsize, zsize, j, i-1, j+1, i-1, j, i, &N);
- k += add_single_normal(map, xsize, zsize, j+1, i, j, i, j+1, i-1, &N);
- */
- k += add_single_normal(map, xsize, zsize, j, i, j+1, i, j, i+1, &N);
- k += add_single_normal(map, xsize, zsize, j, i, j, i+1, j-1, i, &N);
- k += add_single_normal(map, xsize, zsize, j, i, j-1, i, j, i-1, &N);
- k += add_single_normal(map, xsize, zsize, j, i, j, i-1, j+1, i, &N);
-
- if (k == 0)
- {
- fprintf(stderr, "Failed to find any normals at: (%d, %d)\n", i, j);
- exit(1);
- }
- Normalize(&N, &N);
- hf->Normals[i][j][0] = (short)(32767 * N.x);
- hf->Normals[i][j][1] = (short)(32767 * N.y);
- hf->Normals[i][j][2] = (short)(32767 * N.z);
- /* printf("n[%d,%d]: <%g %g %g>\n", j, i, N.x, N.y, N.z); */
- }
- }
- }
-
- void Find_Hf_Min_Max(H_Field, Image)
- HEIGHT_FIELD *H_Field;
- IMAGE *Image;
- {
- int n, i, i2, j, j2, x, z, w, h, max_x, max_z, temp1, temp2;
- DBL size;
- HF_val temp_y;
-
- max_x = Image->iwidth;
- if(Image->File_Type == POT_FILE) max_x = max_x/2;
- max_z = Image->iheight;
-
- size = (DBL)max_value(max_x, max_z);
- H_Field->Block_Size = Block_Size = ceil(sqrt(size+1.0));
- H_Field->Inv_Blk_Size = Inv_Blk_Size = 1.0/Block_Size;
- n = (int)Block_Size;
-
- w = (int)ceil((max_x+1.0)*Inv_Blk_Size);
- h = (int)ceil((max_z+1.0)*Inv_Blk_Size);
-
- H_Field->Map = (HF_val **)calloc(max_z+1, sizeof(HF_val *));
- if (H_Field->Map == NULL)
- fprintf(stderr,"Cannot allocate memory for height field\n");
-
- H_Field->Block = (HF_BLOCK **)calloc(w,sizeof(HF_BLOCK *));
- if(H_Field->Block == NULL)
- fprintf(stderr, "Cannot allocate memory for height field buffer\n");
- for(i=0; i<w; i++)
- {
- H_Field->Block[i] = (HF_BLOCK *)calloc(h,sizeof(HF_BLOCK));
- if (H_Field->Block[i] == NULL)
- fprintf(stderr, "Cannot allocate memory for height field buffer line\n"
- );
- for(j=0; j<h; j++)
- {
- H_Field->Block[i][j].min_y = 65535;
- H_Field->Block[i][j].max_y = 0;
- }
- }
-
- H_Field->Map[0] = (HF_val *)calloc(max_x+1,sizeof(HF_val));
- if (H_Field->Map[0] == NULL)
- fprintf(stderr,"Cannot allocate memory for height field\n");
-
- for(j=0; j < h; j++)
- {
- for(j2=0;(j2 <= n) && (j*n+j2 <= max_z);j2++)
- {
- z = j*n+j2;
- if(j2!=0)
- {
- H_Field->Map[z] = (HF_val *)calloc(max_x+1,sizeof(HF_val));
- if (H_Field->Map[z] == NULL)
- fprintf(stderr, "Cannot allocate memory for height field\n");
- }
-
- COOPERATE
- for(i=0; i < w; i++)
- {
- for(i2=0;(i2 <= n)&&(i*n+i2 <= max_x);i2++)
- {
- x = i*n+i2;
- if((x >= 0) && (x < max_x) && (z >= 0) && (z < max_z))
- {
- switch(Image->File_Type)
- {
- case GIF_FILE:
- temp1 = Image->data.map_lines[max_z - z - 1][x];
- temp_y = (HF_val)(256*temp1);
- break;
- case POT_FILE:
- temp1 = Image->data.map_lines[max_z - z - 1][x];
- temp2 = Image->data.map_lines[max_z - z - 1][x + max_x];
- temp_y = (HF_val)(256*temp1 + temp2);
- break;
- case TGA_FILE:
- if (Image->data.rgb_lines != NULL)
- {
- temp1 = Image->data.rgb_lines[max_z - z - 1].red[x];
- temp2 = Image->data.rgb_lines[max_z - z - 1].green[x];
- }
- else
- {
- temp1 = Image->data.map_lines[max_z - z - 1][x];
- temp2 = 0;
- }
- temp_y = (HF_val)(256*temp1 + temp2);
- break;
- }
- H_Field->Map[z][x] = temp_y;
- }
- else
- {
- if (z == max_z)
- {
- H_Field->Map[z][x] = H_Field->Map[z-1][x];
- }
- if (x == max_x)
- {
- H_Field->Map[z][x] = H_Field->Map[z][x-1];
- }
- temp_y = H_Field->Map[z][x];
- }
-
- if(temp_y < H_Field->Block[i][j].min_y)
- H_Field->Block[i][j].min_y = temp_y;
- if(temp_y > H_Field->Block[i][j].max_y)
- H_Field->Block[i][j].max_y = temp_y;
- }
- }
- if((z >= 0) && (z < max_z) && (j2!=n))
- {
- switch (Image->File_Type)
- {
- case GIF_FILE:
- free(Image->data.map_lines[max_z - z - 1]); break;
- case POT_FILE:
- free(Image->data.map_lines[max_z - z - 1]); break;
- case TGA_FILE:
- if (Image->data.rgb_lines != NULL)
- {
- free(Image->data.rgb_lines[max_z - z - 1].blue);
- free(Image->data.rgb_lines[max_z - z - 1].green);
- free(Image->data.rgb_lines[max_z - z - 1].red);
- }
- else
- {
- free(Image->data.map_lines[max_z - z - 1]);
- }
- break;
- }
- }
- }
- }
-
- /* If this is a smoothed height field, then allocate storage for
- the normals & compute them */
- if (H_Field->Smoothed)
- smooth_height_field(H_Field, max_x, max_z);
-
- }
-
- int All_HeightFld_Intersections(Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- VECTOR Temp1, Temp2;
- RAY Temp_Ray;
- DBL depth1, depth2;
- int ret_val = FALSE;
- HEIGHT_FIELD *H_Field = (HEIGHT_FIELD *) Object;
-
- Ray_Ht_Field_Tests++;
-
- MInvTransPoint(&(Temp_Ray.Initial),&(Ray->Initial),H_Field->Trans);
- MInvTransDirection(&(Temp_Ray.Direction),&(Ray->Direction),H_Field->Trans);
-
- if(!Intersect_Boxx(&Temp_Ray,H_Field->bounding_box,&depth1,&depth2))
- return(FALSE);
-
- H_Field->cache_pos = 0;
- Block_Size = H_Field->Block_Size;
- Inv_Blk_Size = H_Field->Inv_Blk_Size;
-
- if( depth1 == depth2)
- {
- depth1 = Small_Tolerance;
- VScale(Temp1,Temp_Ray.Direction,depth1);
- VAddEq(Temp1,Temp_Ray.Initial);
- VScale(Temp2,Temp_Ray.Direction,depth2);
- VAddEq(Temp2,Temp_Ray.Initial);
- }
- else
- {
- VScale(Temp1,Temp_Ray.Direction,depth1);
- VAddEq(Temp1,Temp_Ray.Initial);
- VScale(Temp2,Temp_Ray.Direction,depth2);
- VAddEq(Temp2,Temp_Ray.Initial);
- }
-
- mindist = depth1;
- maxdist = depth2;
-
- if(fabs(Temp_Ray.Direction.x) > EPSILON)
- {
- Mzx = Temp_Ray.Direction.z/Temp_Ray.Direction.x;
- Myx = Temp_Ray.Direction.y/Temp_Ray.Direction.x;
- }
- else
- {
- Mzx = Temp_Ray.Direction.z/EPSILON;
- Myx = Temp_Ray.Direction.y/EPSILON;
- }
- if(fabs(Temp_Ray.Direction.z) > EPSILON)
- {
- Mxz = Temp_Ray.Direction.x/Temp_Ray.Direction.z;
- Myz = Temp_Ray.Direction.y/Temp_Ray.Direction.z;
- }
- else
- {
- Mxz = Temp_Ray.Direction.x/EPSILON;
- Myz = Temp_Ray.Direction.y/EPSILON;
- }
-
- Hf_Stack = Depth_Stack;
- RRay = Ray;
-
- isdx = sign(Temp_Ray.Direction.x);
- isdz = sign(Temp_Ray.Direction.z);
-
- X_Dom = FALSE;
- if(fabs(Temp_Ray.Direction.x) >= fabs(Temp_Ray.Direction.z))
- X_Dom = TRUE;
-
- Gdx = fabs(Mxz);
- Gdz = fabs(Mzx);
- if(X_Dom)
- {
- Gdy = Myx * (DBL)isdx;
- }
- else
- {
- Gdy = Myz * (DBL)isdz;
- }
-
- if(Intersect_Hf_Node(&Temp_Ray, H_Field, &Temp1, &Temp2))
- ret_val = TRUE;
- return(ret_val);
- }
-
- int All_Csg_HeightFld_Intersections(Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- VECTOR Temp1, Temp2;
- RAY Temp_Ray;
- DBL depth1, depth2;
- int ret_val = FALSE;
- HEIGHT_FIELD *H_Field = (HEIGHT_FIELD *) Object;
-
- Ray_Ht_Field_Tests++;
-
- MInvTransPoint(&(Temp_Ray.Initial),&(Ray->Initial),H_Field->Trans);
- MInvTransDirection(&(Temp_Ray.Direction),&(Ray->Direction),H_Field->Trans);
-
- if(!Intersect_Boxx(&Temp_Ray,H_Field->bounding_box,&depth1,&depth2))
- return(FALSE);
-
- H_Field->cache_pos = 0;
- Block_Size = H_Field->Block_Size;
- Inv_Blk_Size = H_Field->Inv_Blk_Size;
-
- if( depth1 == depth2)
- {
- depth1 = Small_Tolerance;
- VScale(Temp1,Temp_Ray.Direction,depth1);
- VAddEq(Temp1,Temp_Ray.Initial);
- VScale(Temp2,Temp_Ray.Direction,depth2);
- VAddEq(Temp2,Temp_Ray.Initial);
- }
- else
- {
- VScale(Temp1,Temp_Ray.Direction,depth1);
- VAddEq(Temp1,Temp_Ray.Initial);
- VScale(Temp2,Temp_Ray.Direction,depth2);
- VAddEq(Temp2,Temp_Ray.Initial);
- }
-
- mindist = depth1;
- maxdist = depth2;
-
- if(fabs(Temp_Ray.Direction.x) > EPSILON)
- {
- Mzx = Temp_Ray.Direction.z/Temp_Ray.Direction.x;
- Myx = Temp_Ray.Direction.y/Temp_Ray.Direction.x;
- }
- else
- {
- Mzx = Temp_Ray.Direction.z/EPSILON;
- Myx = Temp_Ray.Direction.y/EPSILON;
- }
- if(fabs(Temp_Ray.Direction.z) > EPSILON)
- {
- Mxz = Temp_Ray.Direction.x/Temp_Ray.Direction.z;
- Myz = Temp_Ray.Direction.y/Temp_Ray.Direction.z;
- }
- else
- {
- Mxz = Temp_Ray.Direction.x/EPSILON;
- Myz = Temp_Ray.Direction.y/EPSILON;
- }
-
- Hf_Stack = Depth_Stack;
- RRay = Ray;
-
- isdx = sign(Temp_Ray.Direction.x);
- isdz = sign(Temp_Ray.Direction.z);
-
- X_Dom = FALSE;
- if(fabs(Temp_Ray.Direction.x) >= fabs(Temp_Ray.Direction.z))
- X_Dom = TRUE;
-
- Gdx = fabs(Mxz);
- Gdz = fabs(Mzx);
- if(X_Dom)
- {
- Gdy = Myx * (DBL)isdx;
- }
- else
- {
- Gdy = Myz * (DBL)isdz;
- }
-
- if(Intersect_Csg_Hf_Node(&Temp_Ray, H_Field, &Temp1, &Temp2))
- ret_val = TRUE;
- return(ret_val);
- }
-
- int Inside_HeightFld (IPoint, Object)
- VECTOR *IPoint;
- OBJECT *Object;
- {
- HEIGHT_FIELD *H_Field = (HEIGHT_FIELD *) Object;
- int px, pz;
- DBL x,z,y1,y2,y3,water, dot1, dot2;
- VECTOR Local_Origin, Temp1, Temp2, Local_Normal, Test;
-
- MInvTransPoint(&Test, IPoint, H_Field->Trans);
-
- water = H_Field->bounding_box->bounds[0].y;
- if ((Test.x < 0.0) || (Test.x >= H_Field->bounding_box->bounds[1].x) || (Test.z < 0.0) || (Test.z >= H_Field->bounding_box->bounds[1].z))
- return (H_Field->Inverted);
-
- if (Test.y >= H_Field->bounding_box->bounds[1].y)
- return (H_Field->Inverted);
-
- if (Test.y < water)
- return (H_Field->Inverted ^ TRUE);
-
- px = (int)Test.x;
- pz = (int)Test.z;
- x = Test.x - (DBL)px;
- z = Test.z - (DBL)pz;
-
- if((x+z)<1.0)
- {
- y1 = max_value(Get_Height(px,pz,H_Field),water);
- y2 = max_value(Get_Height(px+1,pz,H_Field),water);
- y3 = max_value(Get_Height(px,pz+1,H_Field),water);
- Make_Vector(&Local_Origin,(DBL)px,y1,(DBL)pz);
- Temp1.x = 1.0;
- Temp1.z = 0.0;
- Temp1.y = y2 - y1;
- Temp2.x = 0.0;
- Temp2.z = 1.0;
- Temp2.y = y3 - y1;
- }
- else
- {
- px = (int)ceil(Test.x);
- pz = (int)ceil(Test.z);
- y1 = max_value(Get_Height(px,pz,H_Field),water);
- y2 = max_value(Get_Height(px-1,pz,H_Field),water);
- y3 = max_value(Get_Height(px,pz-1,H_Field),water);
- Make_Vector(&Local_Origin,(DBL)px,y1,(DBL)pz);
- Temp1.x = -1.0;
- Temp1.z = 0.0;
- Temp1.y = y2 - y1;
- Temp2.x = 0.0;
- Temp2.z = -1.0;
- Temp2.y = y3 - y1;
- }
- VCross(Local_Normal,Temp2,Temp1);
- VDot(dot1,Test,Local_Normal);
- VDot(dot2,Local_Origin,Local_Normal);
- if(dot1 < dot2)
- return(TRUE^H_Field->Inverted);
- return(FALSE^H_Field->Inverted);
- }
-
- static
- DBL stretch (x)
- DBL x;
- {
- if(x<=0.5)
- {
- x = 2 * x*x;
- }
- else
- {
- x = 1.0 - (2 * (1.0-x)*(1.0-x));
- }
- return x;
- }
-
- void HeightFld_Normal (Result, Object, IPoint)
- OBJECT *Object;
- VECTOR *Result, *IPoint;
- {
- HEIGHT_FIELD *H_Field = (HEIGHT_FIELD *) Object;
- int px,pz, i, code;
- DBL x,z,y1,y2,y3,u,v;
- VECTOR Local_Origin, Temp1, Temp2;
- VECTOR n[5];
-
- MInvTransPoint(&Local_Origin, IPoint, H_Field->Trans);
-
- for(i=0;i<H_Field->cache_pos;i++)
- {
- if(((float)Local_Origin.x == H_Field->Normal_Vector[i].x) &&
- ((float)Local_Origin.z == H_Field->Normal_Vector[i].z))
- {
- *Result = H_Field->Normal_Vector[i].normal;
- MTransNormal(Result,Result,H_Field->Trans);
- VNormalize(*Result,*Result);
- return;
- }
- }
-
- px = (int)Local_Origin.x;
- pz = (int)Local_Origin.z;
- x = Local_Origin.x - (DBL)px;
- z = Local_Origin.z - (DBL)pz;
-
- px = (int)Local_Origin.x;
- pz = (int)Local_Origin.z;
- x = Local_Origin.x - (DBL)px;
- z = Local_Origin.z - (DBL)pz;
- if ((x+z) <= 1.0)
- code = LOWER_TRI;
- else
- code = UPPER_TRI;
-
- if (H_Field->Smoothed)
- {
- n[0].x = H_Field->Normals[pz][px][0];
- n[0].y = H_Field->Normals[pz][px][1];
- n[0].z = H_Field->Normals[pz][px][2];
- n[1].x = H_Field->Normals[pz][px+1][0];
- n[1].y = H_Field->Normals[pz][px+1][1];
- n[1].z = H_Field->Normals[pz][px+1][2];
- n[2].x = H_Field->Normals[pz+1][px][0];
- n[2].y = H_Field->Normals[pz+1][px][1];
- n[2].z = H_Field->Normals[pz+1][px][2];
- n[3].x = H_Field->Normals[pz+1][px+1][0];
- n[3].y = H_Field->Normals[pz+1][px+1][1];
- n[3].z = H_Field->Normals[pz+1][px+1][2];
- x = stretch(x);
- z = stretch(z);
- u = (1.0 - x);
- v = (1.0 - z);
-
- /* n[4].x = u*n[0].x + x*n[1].x;
- n[4].y = u*n[0].y + x*n[1].y;
- n[4].z = u*n[0].z + x*n[1].z;
-
- n[5].x = u*n[2].x + x*n[3].x;
- n[5].y = u*n[2].y + x*n[3].y;
- n[5].z = u*n[2].z + x*n[3].z;
-
- n[6].x = v*n[0].x + z*n[2].x;
- n[6].y = v*n[0].y + z*n[2].y;
- n[6].z = v*n[0].z + z*n[2].z;
-
- n[7].x = v*n[1].x + z*n[3].x;
- n[7].y = v*n[1].y + z*n[3].y;
- n[7].z = v*n[1].z + z*n[3].z;
-
- Result->x = u*n[6].x + x*n[7].x + v*n[4].x + z*n[5].x;
- Result->y = u*n[6].y + x*n[7].y + v*n[4].y + z*n[5].y;
- Result->z = u*n[6].z + x*n[7].z + z*n[4].z + v*n[5].z;
- */
- Result->x = u*v*n[0].x + x*v*n[1].x + u*z*n[2].x + x*z*n[3].x;
- Result->y = u*v*n[0].y + x*v*n[1].y + u*z*n[2].y + x*z*n[3].y;
- Result->z = u*v*n[0].z + x*v*n[1].z + u*z*n[2].z + x*z*n[3].z;
- }
- else if (code == LOWER_TRI)
- {
- y1 = Get_Height(px,pz,H_Field);
- y2 = Get_Height(px+1,pz,H_Field);
- y3 = Get_Height(px,pz+1,H_Field);
- Temp1.x = 1.0;
- Temp1.z = 0.0;
- Temp1.y = y2 - y1;
- Temp2.x = 0.0;
- Temp2.z = 1.0;
- Temp2.y = y3 - y1;
- VCross(*Result,Temp2,Temp1);
- }
- else
- {
- y1 = Get_Height(px+1,pz+1,H_Field);
- y2 = Get_Height(px,pz+1,H_Field);
- y3 = Get_Height(px+1,pz,H_Field);
- Temp1.x = -1.0;
- Temp1.z = 0.0;
- Temp1.y = y2 - y1;
- Temp2.x = 0.0;
- Temp2.z = -1.0;
- Temp2.y = y3 - y1;
- VCross(*Result,Temp2,Temp1);
- }
- MTransNormal(Result,Result,H_Field->Trans);
- VNormalize(*Result,*Result);
- return;
- }
-
- void *Copy_HeightFld (Object)
- OBJECT *Object;
- {
- HEIGHT_FIELD *New;
-
- New = Create_Height_Field ();
-
- /* Create_Height_Field creates a transform and a box as
- does Copy_Transform and Copy_Box so destroy these.
- */
-
- Destroy_Transform(New->Trans);
- Destroy_Box((OBJECT *)(New->bounding_box));
-
- *New = *((HEIGHT_FIELD *)Object);
-
- New->Trans = Copy_Transform (((HEIGHT_FIELD *)Object)->Trans);
- New->bounding_box = Copy_Box ((OBJECT *)(((HEIGHT_FIELD *)Object)->bounding_box));
-
- /* Note: For the time being we will not support copying the Block and Map
- arrays. We will only copy the pointers. This means Destroy_HeightFld
- must not destroy these arrays. Actually it cannot because we don't
- really know how big they are!
- */
-
- return (New);
- }
-
- void Translate_HeightFld (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- Compute_Translation_Transform(&Trans,Vector);
- Compose_Transforms(((HEIGHT_FIELD *) Object)->Trans,&Trans);
- }
-
- void Rotate_HeightFld (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- Compute_Rotation_Transform(&Trans,Vector);
- Compose_Transforms(((HEIGHT_FIELD *) Object)->Trans,&Trans);
- }
-
- void Scale_HeightFld (Object, Vector)
- OBJECT *Object;
- VECTOR *Vector;
- {
- TRANSFORM Trans;
-
- Compute_Scaling_Transform(&Trans,Vector);
- Compose_Transforms(((HEIGHT_FIELD *)Object)->Trans,&Trans);
- }
-
- void Invert_HeightFld (Object)
- OBJECT *Object;
- {
- ((HEIGHT_FIELD *)Object)->Inverted ^= TRUE;
- }
-
- void Transform_HeightFld (Object, Trans)
- OBJECT *Object;
- TRANSFORM *Trans;
- {
- Compose_Transforms(((HEIGHT_FIELD *)Object)->Trans, Trans);
- }
-
- /* Allocate and intialize a Height Field */
- HEIGHT_FIELD *Create_Height_Field()
- {
- HEIGHT_FIELD *New;
-
- if((New = (HEIGHT_FIELD *) malloc (sizeof(HEIGHT_FIELD))) == NULL)
- MAError ("height field");
-
- INIT_OBJECT_FIELDS(New, HEIGHT_FIELD_OBJECT, &Height_Field_Methods)
-
- /* Always uses Trans so always create one. */
- New->Trans = Create_Transform ();
- New->bounding_box = Create_Box ();
- New->Block_Size = 1.0;
- New->Inv_Blk_Size = 1.0;
- New->Block = NULL;
- New->Map = NULL;
- New->Inverted = FALSE;
- New->cache_pos = 0;
- New->Smoothed = FALSE;
- New->Normals = NULL;
- return(New);
- }
-
- void Destroy_HeightFld (Object)
- OBJECT *Object;
- {
- Destroy_Transform (((HEIGHT_FIELD *)Object)->Trans);
- Destroy_Box ((OBJECT *)((HEIGHT_FIELD *)Object)->bounding_box);
- free (Object);
- }
-