1
// Various math & other functions
8
#define _USE_MATH_DEFINES
18
//------------------------------------------------------------------------------
19
// various template functions
21
// returns absolute value of x
23
inline T ABS(T x) { return (x < (T)0) ? -x : x; }
25
// to be used with points/vectors, mostly to test ccw or cw order
26
// returns twice the (signed) area of triangle defined by vertices (a, b, c)
28
inline float signedArea2X(const T &a, const T &b, const T &c)
30
return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
33
// 2D Signed Triangle Area
35
inline float tri_area(const T &a, const T &b, const T &c)
37
return 0.5f*((b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y));
40
// 2D Signed Quad Area
42
inline float quad_area(const T &a, const T &b, const T &c, const T &d)
44
return 0.5f*((c.x - a.x)*(d.y - b.y) - (d.x - b.x)*(c.y - a.y));
47
// Intersection test of two 2D line segments, returns intersect time along first segment, -1 if no intersection
49
inline float segInt(const T &s1, const T &e1, const T &s2, const T &e2)
51
const float dx11 = e1.x - s1.x, dx22 = e2.x - s2.x;
52
const float dy11 = e1.y - s1.y, dy22 = e2.y - s2.y;
53
const float d = dy22*dx11 - dx22*dy11;
54
if (d == 0.f) return -1.f;
55
const float dx12 = s1.x - s2.x, dy12 = s1.y - s2.y;
56
const float a = dx22*dy12 - dy22*dx12, b = dx11*dy12 - dy11*dx12;
57
const float u1 = a / d;
58
if ((u1 < 0.f) || (u1 > 1.f)) return -1.f;
59
const float u2 = b / d;
60
return ((u2 < 0.f) || (u2 > 1.f)) ? -1.f : u1;
63
// Area of completely general quad
65
inline float gQuad_area(const T &a, const T &b, const T &c, const T &d)
67
// test if any two opposite segments intersect,
68
// if so, return sum of area of the two triangles connected at intersection point,
69
// otherwise, do direct area computation which also works for concave quads.
70
float u = segInt(a, b, c, d);
72
const T ip = a + u*(b - a);
73
return ABS(tri_area(a, ip, d)) + ABS(tri_area(b, ip, c));
75
u = segInt(a, d, b, c);
77
const T ip = a + u*(d - a);
78
return ABS(tri_area(a, b, ip)) + ABS(tri_area(c, d, ip));
80
return ABS(quad_area(a, b, c, d));
83
// returns minimum of two elements
85
inline T MIN2(T a, T b)
87
return (a < b) ? a : b;
90
// returns maximum of two elements
92
inline T MAX2(T a, T b)
94
return (a > b) ? a : b;
97
// returns minimum of four elements
99
inline T MIN4(T a, T b, T c, T d)
101
return MIN2(a, MIN2(b, MIN2(c, d)));
104
// returns maximum of four elements
106
inline T MAX4(T a, T b, T c, T d)
108
return MAX2(a, MAX2(b, MAX2(c, d)));
111
// swaps contents of two objects
113
inline void SWAP(T &a, T &b)
120
// clamp value to zero if negative
124
return (v < (T)0) ? ((T)0) : v;
127
// clamp value in range [min, max]
129
inline T CLAMP(T a, T min, T max)
131
return ((a < min) ? min : ((a > max) ? max : a));
136
inline T SIGN(T x) { return (x==(T)0) ? 0 : ((x<(T)0) ? (T)-1 : (T)1); }
138
//----------------------------------------------------------------------------------
139
// General simple C based math routines mainly used by the shader virtual machine,
140
// most vector functions are also used for points/normals and colors.
141
// For the cases where the difference matters, explicit routines exist,
142
// eg. matrix vector & point multiply .etc.
143
// General format is func(result, var1, var2, ...)
144
// For all functions where operands are the same type as the result type,
145
// the result variable can be the same as either of the operands, eg. cross(v1, v1, v2)
146
//----------------------------------------------------------------------------------
148
inline RtVoid addVVV(RtVector r, const RtVector v1, const RtVector v2)
150
r[0] = v1[0] + v2[0];
151
r[1] = v1[1] + v2[1];
152
r[2] = v1[2] + v2[2];
155
inline RtVoid subVVV(RtVector r, const RtVector v1, const RtVector v2)
157
r[0] = v1[0] - v2[0];
158
r[1] = v1[1] - v2[1];
159
r[2] = v1[2] - v2[2];
162
inline RtVoid mulVVV(RtVector r, const RtVector v1, const RtVector v2)
164
r[0] = v1[0] * v2[0];
165
r[1] = v1[1] * v2[1];
166
r[2] = v1[2] * v2[2];
169
inline RtVoid maddVVV(RtVector r, const RtVector v1, const RtVector v2)
171
r[0] += v1[0] * v2[0];
172
r[1] += v1[1] * v2[1];
173
r[2] += v1[2] * v2[2];
176
inline RtVoid msubVVV(RtVector r, const RtVector v1, const RtVector v2)
178
r[0] -= v1[0] * v2[0];
179
r[1] -= v1[1] * v2[1];
180
r[2] -= v1[2] * v2[2];
183
inline RtVoid divVVV(RtVector r, const RtVector v1, const RtVector v2)
185
if (v2[0] != 0.f) r[0] = v1[0] / v2[0];
186
if (v2[1] != 0.f) r[1] = v1[1] / v2[1];
187
if (v2[2] != 0.f) r[2] = v1[2] / v2[2];
190
inline RtVoid mulVVF(RtVector r, const RtVector v, const RtFloat f)
197
inline RtVoid maddVVF(RtVector r, const RtVector v, const RtFloat f)
204
inline RtVoid msubVVF(RtVector r, const RtVector v, const RtFloat f)
211
inline RtVoid divVVF(RtVector r, const RtVector v, RtFloat f)
221
inline RtVoid mulVV(RtVector r, const RtVector v)
228
inline RtVoid vcross(RtVector r, const RtVector v1, const RtVector v2)
230
const RtFloat x = v1[1]*v2[2] - v1[2]*v2[1];
231
const RtFloat y = v1[2]*v2[0] - v1[0]*v2[2];
232
r[2] = v1[0]*v2[1] - v1[1]*v2[0];
237
inline RtVoid vdot(RtFloat &r, const RtVector v1, const RtVector v2)
239
r = v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
242
inline RtVoid vnormalize(RtVector r, const RtVector v)
244
RtFloat d = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
253
// sets the length of v to L
254
inline RtVoid vsetlength(RtVector r, const RtVector v, float L)
256
RtFloat d = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
265
inline RtVoid vlength(RtFloat &r, const RtVector v)
267
r = sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
271
inline RtVoid step(RtFloat &r, const RtFloat min, const RtFloat val)
273
r = (val < min) ? 0.f : 1.f;
276
inline RtVoid smoothstep(RtFloat &r, const RtFloat min, const RtFloat max, RtFloat val)
283
val = (val - min) / (max - min);
284
r = val*val*(3.f - 2.f*val);
289
inline RtVoid faceforward(RtVector r, const RtVector v1, const RtVector v2, const RtVector v3)
291
// assumes v1 = N, I = v2, v3 = Ng|Nref
292
const RtFloat d = ((-v2[0]*v3[0] - v2[1]*v3[1] - v2[2]*v3[2]) < 0.f) ? -1.f : 1.f;
298
// float linear interpolation
299
inline RtVoid mixf(RtFloat &r, const RtFloat f0, const RtFloat f1, const RtFloat v)
301
r = f0 + v*(f1 - f0);
304
// color/point/vector/normal linear interpolation
305
inline RtVoid mixv(RtVector r, const RtVector c0, const RtVector c1, const RtFloat v)
307
r[0] = c0[0] + v*(c1[0] - c0[0]);
308
r[1] = c0[1] + v*(c1[1] - c0[1]);
309
r[2] = c0[2] + v*(c1[2] - c0[2]);
312
// conversion of degrees to radians
313
inline RtVoid radians(RtFloat &r, const RtFloat d)
315
r = d * ((RtFloat)M_PI/180.f);
318
// conversion of radians to degrees
319
inline RtVoid degrees(RtFloat &r, const RtFloat d)
321
r = d * (180.f/(RtFloat)M_PI);
324
// bilinear interpolation (other float[3] types can be used too, RtPoint/RtVector/etc)
325
inline void bilerp(RtColor r, RtFloat u, RtFloat v,
326
const RtColor c00, const RtColor c10, const RtColor c01, const RtColor c11)
328
const RtFloat w00=(1.f-u)*(1.f-v), w10=u*(1.f-v), w01=(1.f-u)*v, w11=u*v;
329
r[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
330
r[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
331
r[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
334
// bilinear interpolation of single floats
335
inline void bilerpF(RtFloat &r, RtFloat u, RtFloat v,
336
RtFloat f00, RtFloat f10, RtFloat f01, RtFloat f11)
338
r = (1.f-v)*((1.f-u)*f00 + u*f10) + v*((1.f-u)*f01 + u*f11);
342
inline void reflect(RtVector r, const RtVector I, const RtVector N)
344
const RtFloat ndi2 = 2.f*(N[0]*I[0] + N[1]*I[1] + N[2]*I[2]);
345
r[0] = I[0] - ndi2*N[0];
346
r[1] = I[1] - ndi2*N[1];
347
r[2] = I[2] - ndi2*N[2];
351
inline void refract(RtVector r, const RtVector I, const RtVector N, const RtFloat eta)
353
const RtFloat ndi = N[0]*I[0] + N[1]*I[1] + N[2]*I[2];
354
const RtFloat k = 1.f - eta*eta*(1.f - ndi*ndi);
356
r[0] = r[1] = r[2] = 0.f;
358
const RtFloat f = eta*ndi + sqrtf(k);
359
r[0] = eta*I[0] - f*N[0];
360
r[1] = eta*I[1] - f*N[1];
361
r[2] = eta*I[2] - f*N[2];
365
void fresnel(const RtVector I, const RtVector N, const float eta, float& Kr, float& Kt, RtVector R = NULL, RtVector T = NULL);
367
//------------------------------------------------------------------------------
370
RtVoid addMMM(RtMatrix r, const RtMatrix m1, const RtMatrix m2);
371
RtVoid subMMM(RtMatrix r, const RtMatrix m1, const RtMatrix m2);
372
RtVoid mulMMM(RtMatrix r, const RtMatrix m1, const RtMatrix m2);
373
RtBoolean invertMatrix(RtMatrix minv, const RtMatrix m2);
375
inline RtVoid transposeM(RtMatrix r)
377
SWAP(r[0][1], r[1][0]);
378
SWAP(r[0][2], r[2][0]);
379
SWAP(r[0][3], r[3][0]);
380
SWAP(r[2][1], r[1][2]);
381
SWAP(r[3][2], r[2][3]);
382
SWAP(r[3][1], r[1][3]);
385
inline RtVoid divMMM(RtMatrix r, const RtMatrix m1, const RtMatrix m2)
388
assert(invertMatrix(im2, m2));
392
inline RtVoid mulVMV(RtVector r, const RtMatrix m, const RtVector v)
394
const RtFloat x = v[0], y = v[1];
395
r[0] = m[0][0]*x + m[0][1]*y + m[0][2]*v[2];
396
r[1] = m[1][0]*x + m[1][1]*y + m[1][2]*v[2];
397
r[2] = m[2][0]*x + m[2][1]*y + m[2][2]*v[2];
400
inline RtVoid mulNMN(RtNormal r, const RtMatrix m, const RtNormal n)
402
// normal, multiply by inverse of transpose (could be optimized, don't need to recalculate everytime)
404
assert(invertMatrix(m2, m));
405
const RtFloat x = n[0], y = n[1];
406
r[0] = m2[0][0]*x + m2[1][0]*y + m2[2][0]*n[2];
407
r[1] = m2[0][1]*x + m2[1][1]*y + m2[2][1]*n[2];
408
r[2] = m2[0][2]*x + m2[1][2]*y + m2[2][2]*n[2];
411
inline RtVoid mulPMP(RtPoint r, const RtMatrix m, const RtPoint p)
413
const RtFloat x = p[0], y = p[1], z = p[2];
414
r[0] = m[0][0]*x + m[0][1]*y + m[0][2]*z + m[0][3];
415
r[1] = m[1][0]*x + m[1][1]*y + m[1][2]*z + m[1][3];
416
r[2] = m[2][0]*x + m[2][1]*y + m[2][2]*z + m[2][3];
417
const RtFloat w = m[3][0]*x + m[3][1]*y + m[3][2]*z + m[3][3];
418
if (w != 1.f) divVVF(r, r, w);
421
inline RtVoid mulPMP4(RtHpoint r, const RtMatrix m, const RtHpoint p)
423
const RtFloat x = p[0], y = p[1], z = p[2];
424
r[0] = m[0][0]*x + m[0][1]*y + m[0][2]*z + m[0][3]*p[3];
425
r[1] = m[1][0]*x + m[1][1]*y + m[1][2]*z + m[1][3]*p[3];
426
r[2] = m[2][0]*x + m[2][1]*y + m[2][2]*z + m[2][3]*p[3];
427
r[3] = m[3][0]*x + m[3][1]*y + m[3][2]*z + m[3][3]*p[3];
430
//------------------------------------------------------------------------------
431
// Not sure what the purpose of the below floor/ceil/fmod functions was anymore,
432
// kind of superfluous, could just as well use the actual math funcs...
434
// returns highest integer <= x as float
435
inline float FLOORF(float x)
437
const float r = float(int(x));
438
return ((x >= 0.f) || (r == x)) ? r : (r - 1.f);
441
// returns lowest integer >= x as float
442
inline float CEILF(float x)
444
const float r = float(int(x));
445
return ((x <= 0.f) || (r == x)) ? r : (r + 1.f);
448
// returns highest integer <= x as integer
449
inline int FLOORI(float x)
451
if (x >= 0.f) return int(x);
452
const int r = int(x);
453
return (float(r) == x) ? r : (r - 1);
456
// returns lowest integer >= x as integer
457
inline int CEILI(float x)
459
if (x <= 0.f) return int(x);
460
const int r = int(x);
461
return (float(r) == x) ? r : (r + 1);
464
// returns float x modulo y, return value is in range (0, y)
465
inline float FMOD(float x, float y)
468
return y*(z - FLOORF(z));
471
// returns integer log2 of x (== highest set bit)
472
inline unsigned int ilog2(unsigned int x)
479
// as above, but always rounds upwards
480
inline unsigned int ilog2_roundup(unsigned int x)
482
unsigned int xx = x, b = 0;
483
while (xx >>= 1) b++;
484
return b + (unsigned int)((unsigned int)(1 << b) < x);
487
// direct bicubic evaluation funcs
488
// direct Bezier eval. at value t
489
inline Point3 Bezier(float t, const Point3 &p0, const Point3 &p1, const Point3 &p2, const Point3 &p3)
491
const float tm = 1.f - t;
492
return (3.f*tm*p1 + 3.f*t*p2)*tm*t + tm*tm*tm*p0 + t*t*t*p3;
495
// derivative of Bezier
496
inline void BezierDeriv(float t, const RtPoint p0, const RtPoint p1, const RtPoint p2, const RtPoint p3, RtPoint bd)
498
// for now the more complicated form here
499
bd[0] = (-p0[0] + 3.f*p1[0] + (-3.f*p2[0]) + p3[0])*3.f*t*t + (3.f*p0[0] + (-6.f*p1[0]) + 3.f*p2[0])*2.f*t + (-3.f*p0[0] + 3.f*p1[0]);
500
bd[1] = (-p0[1] + 3.f*p1[1] + (-3.f*p2[1]) + p3[1])*3.f*t*t + (3.f*p0[1] + (-6.f*p1[1]) + 3.f*p2[1])*2.f*t + (-3.f*p0[1] + 3.f*p1[1]);
501
bd[2] = (-p0[2] + 3.f*p1[2] + (-3.f*p2[2]) + p3[2])*3.f*t*t + (3.f*p0[2] + (-6.f*p1[2]) + 3.f*p2[2])*2.f*t + (-3.f*p0[2] + 3.f*p1[2]);
504
// direct evaluation using Power basis
505
inline Point3 Power(float t, const Point3 &p0, const Point3 &p1, const Point3 &p2, const Point3 &p3)
507
return ((p0*t + p1)*t + p2)*t + p3;
510
// direct bicubic curve eval. at value t, arbitrary basis b
511
inline void SplineF(RtFloat& r, const float t, const RtBasis &b, const RtFloat &f0, const RtFloat &f1, const RtFloat &f2, const RtFloat &f3)
513
r = (((b[0][0]*f0 + b[0][1]*f1 + b[0][2]*f2 + b[0][3]*f3) *t
514
+ (b[1][0]*f0 + b[1][1]*f1 + b[1][2]*f2 + b[1][3]*f3))*t
515
+ (b[2][0]*f0 + b[2][1]*f1 + b[2][2]*f2 + b[2][3]*f3))*t
516
+ (b[3][0]*f0 + b[3][1]*f1 + b[3][2]*f2 + b[3][3]*f3);
519
inline void SplineV(RtVector r, const float t, const RtBasis &b, const RtVector &v0, const RtVector &v1, const RtVector &v2, const RtVector &v3)
521
SplineF(r[0], t, b, v0[0], v1[0], v2[0], v3[0]);
522
SplineF(r[1], t, b, v0[1], v1[1], v2[1], v3[1]);
523
SplineF(r[2], t, b, v0[2], v1[2], v2[2], v3[2]);
526
// Bezier eval. using de Casteljau method
527
inline void deCasteljau_P(float t, const RtPoint* cp, RtPoint P)
529
// osculating plane -> tangent -> point
531
#define CAS(a, b, c, d, r) \
532
d0 = a + t*(b - a); \
533
d1 = b + t*(c - b); \
534
d2 = c + t*(d - c); \
537
r = d0 + t*(d1 - d0);
538
CAS(cp[0][0], cp[1][0], cp[2][0], cp[3][0], P[0])
539
CAS(cp[0][1], cp[1][1], cp[2][1], cp[3][1], P[1])
540
CAS(cp[0][2], cp[1][2], cp[2][2], cp[3][2], P[2])
544
// as above, but also returns v tangent in dPdv
545
inline void deCasteljau_P_dPdv(float t, const RtPoint* cp, RtPoint P, RtVector dPdv)
548
#define CAS(a, b, c, d, r, rt) \
549
d0 = a + t*(b - a); \
550
d1 = b + t*(c - b); \
551
d2 = c + t*(d - c); \
554
r = d0 + t*(rt = d1 - d0); \
556
CAS(cp[0][0], cp[1][0], cp[2][0], cp[3][0], P[0], dPdv[0])
557
CAS(cp[0][1], cp[1][1], cp[2][1], cp[3][1], P[1], dPdv[1])
558
CAS(cp[0][2], cp[1][2], cp[2][2], cp[3][2], P[2], dPdv[2])
562
// as above, but only returns u tangent vector instead
563
inline void deCasteljau_dPdu(float t, const RtPoint* cp, RtVector dPdu)
566
#define CAS(a, b, c, d, r) \
567
d0 = a + t*(b - a); \
568
d1 = b + t*(c - b); \
569
d2 = c + t*(d - c); \
573
CAS(cp[0][0], cp[1][0], cp[2][0], cp[3][0], dPdu[0])
574
CAS(cp[0][1], cp[1][1], cp[2][1], cp[3][1], dPdu[1])
575
CAS(cp[0][2], cp[1][2], cp[2][2], cp[3][2], dPdu[2])
579
// version of deCasteljau_P() which can used for c.pts not in array
580
inline void deCasteljau_P(float t, const RtPoint cp0, const RtPoint cp1,
581
const RtPoint cp2, const RtPoint cp3, RtPoint P)
584
#define CAS(a, b, c, d, r) \
585
d0 = a + t*(b - a); \
586
d1 = b + t*(c - b); \
587
d2 = c + t*(d - c); \
590
r = d0 + t*(d1 - d0);
591
CAS(cp0[0], cp1[0], cp2[0], cp3[0], P[0])
592
CAS(cp0[1], cp1[1], cp2[1], cp3[1], P[1])
593
CAS(cp0[2], cp1[2], cp2[2], cp3[2], P[2])