1 /*
2  * vecmath.c
3  *
4  * Copyright (C) 1989, 1991, Craig E. Kolb
5  * All rights reserved.
6  *
7  * This software may be freely copied, modified, and redistributed
8  * provided that this copyright notice is preserved on all copies.
9  *
10  * You may not distribute this software, in whole or in part, as part of
11  * any commercial product without the express consent of the authors.
12  *
13  * There is no warranty or other guarantee of fitness of this software
14  * for any purpose.  It is provided solely "as is".
15  *
16  * $Id: vecmath.c,v 4.0.1.2 91/11/26 21:36:15 cek Exp Locker: cek $
17  *
18  * $Log:	vecmath.c,v $
19  * Revision 4.0.1.2  91/11/26  21:36:15  cek
20  * patch3: Potential roundoff problems.
21  *
22  * Revision 4.0.1.1  91/09/29  15:38:41  cek
23  * patch1: Fixed floating-point compare in normalization code.
24  *
25  * Revision 4.0  91/07/17  14:33:02  kolb
26  * Initial version.
27  *
28  */
29 #include "common.h"
30 
31 /*
32  * Normalize a vector, return original length.
33  */
34 Float
VecNormalize(a)35 VecNormalize(a)
36 register Vector *a;
37 {
38 	Float d;
39 
40 	d = sqrt(a->x*a->x + a->y*a->y + a->z*a->z);
41 	if (equal(d, 0.))
42 		return 0.;
43 	a->x /= d;
44 	a->y /= d;
45 	a->z /= d;
46 #ifdef CRAY
47 	/*
48 	 * The Cray Research Inc. math functional units don't work in the IEEE
49 	 * standard way, so when we get here, we just might have an x,y or z
50 	 * that is not in the range  -1.0 <= J <= 1.0 Yes, I know that that
51 	 * can't happen, but it does. So since we know we just normalized this
52 	 * vector, we'll just force x,y and z into the range -1.0 to 1.0 O.K?
53 	 */
54 	if (a->x >= 1.0) a->x = 1.0;
55 	else if (a->x <= -1.0) a->x = -1.0;
56 	if (a->y >= 1.0) a->y = 1.0;
57 	else if (a->y <= -1.0) a->y = -1.0;
58 	if (a->z >= 1.0) a->z = 1.0;
59 	else if (a->z <= -1.0) a->z = -1.0;
60 #endif /* CRAY */
61 
62 	return d;
63 }
64 
65 /*
66  * Compute cross-product of a and b, place normalized result in o.  Returns
67  * length of result before normalization.
68  */
69 Float
VecNormCross(a,b,r)70 VecNormCross(a, b, r)
71 Vector *a, *b, *r;
72 {
73 	VecCross(a, b, r);
74 	return VecNormalize(r);
75 }
76 
77 /*
78  * Compute cross-product of a and b, place result in o.
79  */
80 void
VecCross(a,b,r)81 VecCross(a, b, r)
82 Vector *a, *b, *r;
83 {
84 	r->x = (a->y * b->z) - (a->z * b->y);
85 	r->y = (a->z * b->x) - (a->x * b->z);
86 	r->z = (a->x * b->y) - (a->y * b->x);
87 }
88 
89 /*
90  * Calculate direction of refracted ray using Heckbert's formula.  Returns TRUE
91  * if a total internal reflection occurs.
92  */
93 int
Refract(dir,from_index,to_index,I,N,cos1)94 Refract(dir, from_index, to_index, I, N, cos1)
95 Float from_index, to_index, cos1;
96 Vector *dir, *I, *N;
97 {
98 	double kn, cos2, k;
99 	Vector nrm;
100 
101 	if (cos1 < 0.) {
102 		/*
103 		 * Hit the 'backside' of a surface -- flip the normal.
104 		 */
105 		nrm.x = -N->x;
106 		nrm.y = -N->y;
107 		nrm.z = -N->z;
108 		cos1 = -cos1;
109 	} else
110 		nrm = *N;
111 
112 	kn = from_index / to_index;
113 	cos2 = 1. - kn*kn*(1. - cos1*cos1);
114 	if (cos2 < 0.)
115 		return TRUE;		/* Total internal reflection. */
116 	k = kn * cos1 - sqrt((double)cos2);
117 	VecComb(kn, *I, k, nrm, dir);
118 	return FALSE;
119 }
120 
121 /*
122  * Given a vector, find two additional vectors such that all three
123  * are mutually perpendicular and uaxis X vaxis = vector.  The given
124  * vector need not be normalized. uaxis and vaxis are normalized.
125  */
126 void
VecCoordSys(vector,uaxis,vaxis)127 VecCoordSys(vector, uaxis, vaxis)
128 Vector *vector, *uaxis, *vaxis;
129 {
130 	uaxis->x = -vector->y;
131 	uaxis->y = vector->x;
132 	uaxis->z = 0.;
133 	if (VecNormalize(uaxis) == 0.) {
134 		uaxis->x = vector->z;
135 		uaxis->y = 0.;
136 		uaxis->z = -vector->x;
137 		if (VecNormalize(uaxis) == 0.)
138 			RLerror(RL_WARN,
139 				"VecCoordSys passed degenerate vector.\n");
140 	}
141 	(void)VecNormCross(vector, uaxis, vaxis);
142 }
143 
144 /*
145  * Modify given normal by "bumping" it.
146  */
147 void
MakeBump(norm,dpdu,dpdv,fu,fv)148 MakeBump(norm, dpdu, dpdv, fu, fv)
149 Vector *norm, *dpdu, *dpdv;	/* normal, surface derivatives */
150 Float fu, fv;			/* bump function partial derivatives in uv */
151 {
152 	Vector tmp1, tmp2;
153 
154 	VecCross(norm, dpdv, &tmp1);
155 	VecScale(fu, tmp1, &tmp1);
156 	VecCross(norm, dpdu, &tmp2);
157 	VecScale(fv, tmp2, &tmp2);
158 	VecSub(tmp1, tmp2, &tmp1);
159 	VecAdd(*norm, tmp1, norm);
160 	(void)VecNormalize(norm);
161 }
162