GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/echo/intx.c Lines: 0 347 0.0 %
Date: 2017-05-26 Branches: 0 207 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "echo.h"
25
#include "privateEcho.h"
26
27
/*
28
** TODO: do whatever possible to minimize the amount of work
29
** needed for shadow rays
30
*/
31
32
int _echoVerbose = 0;
33
34
/*
35
** ALL of the intersection functions are responsible for setting
36
** 1) intx->norm to a NORMALIZED direction
37
** 2) intx->t
38
** 3) intx->obj
39
** Specifically, these things must be set for non-shadow rays.  Setting
40
** them for shadow rays is optional. Setting intx->u and intx->v texture
41
** coords is always optional.
42
**
43
** Setting intx->pos and intx->view (normalized) is done by echoRayIntx
44
*/
45
46
int
47
_echoRayIntx_Noop(RAYINTX_ARGS(Object)) {
48
49
  AIR_UNUSED(intx);
50
  AIR_UNUSED(ray);
51
  AIR_UNUSED(obj);
52
  AIR_UNUSED(parm);
53
  AIR_UNUSED(tstate);
54
  return 0;
55
}
56
57
int
58
_echoRayIntx_CubeSurf(echoPos_t *tP, int *axP, int *dirP,
59
                      echoPos_t xmin, echoPos_t xmax,
60
                      echoPos_t ymin, echoPos_t ymax,
61
                      echoPos_t zmin, echoPos_t zmax,
62
                      echoRay *ray) {
63
  echoPos_t txmin, tymin, tzmin, txmax, tymax, tzmax,
64
    dx, dy, dz, ox, oy, oz, tmin, tmax;
65
  int axmin, axmax, sgn[3];
66
67
  ELL_3V_GET(dx, dy, dz, ray->dir);
68
  ELL_3V_GET(ox, oy, oz, ray->from);
69
  if (dx >= 0) { txmin = (xmin - ox)/dx; txmax = (xmax - ox)/dx; sgn[0] = -1; }
70
  else         { txmin = (xmax - ox)/dx; txmax = (xmin - ox)/dx; sgn[0] =  1; }
71
  if (dy >= 0) { tymin = (ymin - oy)/dy; tymax = (ymax - oy)/dy; sgn[1] = -1; }
72
  else         { tymin = (ymax - oy)/dy; tymax = (ymin - oy)/dy; sgn[1] =  1; }
73
  if (dz >= 0) { tzmin = (zmin - oz)/dz; tzmax = (zmax - oz)/dz; sgn[2] = -1; }
74
  else         { tzmin = (zmax - oz)/dz; tzmax = (zmin - oz)/dz; sgn[2] =  1; }
75
  if (txmin > tymin) { tmin = txmin; axmin = 0; }
76
  else               { tmin = tymin; axmin = 1; }
77
  if (tzmin > tmin)  { tmin = tzmin; axmin = 2; }
78
  if (txmax < tymax) { tmax = txmax; axmax = 0; }
79
  else               { tmax = tymax; axmax = 1; }
80
  if (tzmax < tmax)  { tmax = tzmax; axmax = 2; }
81
  if (tmin >= tmax)
82
    return AIR_FALSE;
83
  *tP = tmin;
84
  *axP = axmin;
85
  *dirP = sgn[axmin];
86
  if (!AIR_IN_CL(ray->neer, tmin, ray->faar)) {
87
    *tP = tmax;
88
    *axP = axmax;
89
    *dirP = -sgn[axmax];
90
    if (!AIR_IN_CL(ray->neer, tmax, ray->faar)) {
91
      return AIR_FALSE;
92
    }
93
  }
94
  return AIR_TRUE;
95
}
96
97
int
98
_echoRayIntx_CubeSolid(echoPos_t *tminP, echoPos_t *tmaxP,
99
                       echoPos_t xmin, echoPos_t xmax,
100
                       echoPos_t ymin, echoPos_t ymax,
101
                       echoPos_t zmin, echoPos_t zmax,
102
                       echoRay *ray) {
103
  echoPos_t txmin, tymin, tzmin, txmax, tymax, tzmax,
104
    dx, dy, dz, ox, oy, oz, tmin, tmax;
105
106
  ELL_3V_GET(dx, dy, dz, ray->dir);
107
  ELL_3V_GET(ox, oy, oz, ray->from);
108
  if (dx >= 0) { txmin = (xmin - ox)/dx; txmax = (xmax - ox)/dx; }
109
  else         { txmin = (xmax - ox)/dx; txmax = (xmin - ox)/dx; }
110
  if (dy >= 0) { tymin = (ymin - oy)/dy; tymax = (ymax - oy)/dy; }
111
  else         { tymin = (ymax - oy)/dy; tymax = (ymin - oy)/dy; }
112
  if (dz >= 0) { tzmin = (zmin - oz)/dz; tzmax = (zmax - oz)/dz; }
113
  else         { tzmin = (zmax - oz)/dz; tzmax = (zmin - oz)/dz; }
114
  if (txmin > tymin) tmin = txmin;
115
  else               tmin = tymin;
116
  if (tzmin > tmin)  tmin = tzmin;
117
  if (txmax < tymax) tmax = txmax;
118
  else               tmax = tymax;
119
  if (tzmax < tmax)  tmax = tzmax;
120
  if (tmin >= tmax)
121
    return AIR_FALSE;
122
123
  if ( ray->faar < tmin || ray->neer > tmax )
124
    return AIR_FALSE;
125
126
  *tminP = AIR_MAX(tmin, ray->neer);
127
  *tmaxP = AIR_MIN(tmax, ray->faar);
128
  return AIR_TRUE;
129
}
130
131
int
132
_echoRayIntx_Sphere(RAYINTX_ARGS(Sphere)) {
133
  echoPos_t t, A, B, C, r[3], dscr, pos[3], tmp;
134
135
  AIR_UNUSED(parm);
136
  AIR_UNUSED(tstate);
137
  ELL_3V_SUB(r, ray->from, obj->pos);
138
  A = ELL_3V_DOT(ray->dir, ray->dir);
139
  B = 2*ELL_3V_DOT(ray->dir, r);
140
  C = ELL_3V_DOT(r, r) - obj->rad*obj->rad;
141
  dscr = B*B - 4*A*C;
142
  if (dscr <= 0) {
143
    /* grazes or misses (most common case) */
144
    return AIR_FALSE;
145
  }
146
  /* else */
147
  dscr = sqrt(dscr);
148
  t = (-B - dscr)/(2*A);
149
  if (!AIR_IN_CL(ray->neer, t, ray->faar)) {
150
    t = (-B + dscr)/(2*A);
151
    if (!AIR_IN_CL(ray->neer, t, ray->faar)) {
152
      return AIR_FALSE;
153
    }
154
  }
155
  /* else one of the intxs is in [neer,faar] segment */
156
  intx->t = t;
157
  ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir);
158
  ELL_3V_SUB(intx->norm, pos, obj->pos);
159
  ELL_3V_NORM(intx->norm, intx->norm, tmp);
160
  intx->obj = OBJECT(obj);
161
  /* does NOT set u, v */
162
  return AIR_TRUE;
163
}
164
165
void
166
_echoRayIntxUV_Sphere(echoIntx *intx) {
167
  echoPos_t u, v;
168
169
  if (intx->norm[0] || intx->norm[1]) {
170
    u = atan2(intx->norm[1], intx->norm[0]);
171
    intx->u = AIR_AFFINE(-AIR_PI, u, AIR_PI, 0.0, 1.0);
172
    v = -asin(intx->norm[2]);
173
    intx->v = AIR_AFFINE(-AIR_PI/2, v, AIR_PI/2, 0.0, 1.0);
174
  }
175
  else {
176
    intx->u = 0;
177
    /* this is valid because if we're here, then intx->norm[2]
178
       is either 1.0 or -1.0 */
179
    intx->v = AIR_AFFINE(1.0, intx->norm[2], -1.0, 0.0, 1.0);
180
  }
181
}
182
183
int
184
_echoRayIntx_Cylinder(RAYINTX_ARGS(Cylinder)) {
185
  echoPos_t A, B, C, aa, bb, cc, dd, ee, ff, dscr, cylt1, cylt2, t, tmax,
186
    twot[2], cylp1, cylp2, pos[3], tmp;
187
  int tidx, radi0, radi1, twocap[2], cap;
188
189
  AIR_UNUSED(parm);
190
  AIR_UNUSED(tstate);
191
192
  if (!_echoRayIntx_CubeSolid(&t, &tmax,
193
                              -1-ECHO_EPSILON, 1+ECHO_EPSILON,
194
                              -1-ECHO_EPSILON, 1+ECHO_EPSILON,
195
                              -1-ECHO_EPSILON, 1+ECHO_EPSILON, ray)) {
196
    return AIR_FALSE;
197
  }
198
  switch(obj->axis) {
199
  case 0:
200
    radi0 = 1; radi1 = 2;
201
    break;
202
  case 1:
203
    radi0 = 0; radi1 = 2;
204
    break;
205
  case 2: default:
206
    radi0 = 0; radi1 = 1;
207
    break;
208
  }
209
  aa = ray->dir[radi0];
210
  bb = ray->dir[radi1];
211
  ee = ray->dir[obj->axis];
212
  cc = ray->from[radi0];
213
  dd = ray->from[radi1];
214
  ff = ray->from[obj->axis];
215
  A = aa*aa + bb*bb;
216
  B = 2*(aa*cc + bb*dd);
217
  C = cc*cc + dd*dd - 1;
218
  dscr = B*B - 4*A*C;
219
  if (dscr <= 0) {
220
    /* infinite ray grazes or misses the infinite cylinder (not
221
       bounded to [-1,1] along cylinder's axis), so therefore the ray
222
       grazes or misses the actual cylinder */
223
    return AIR_FALSE;
224
  }
225
  /* else infinite ray intersects the infinite cylinder */
226
  dscr = sqrt(dscr);
227
  cylt1 = (-B - dscr)/(2*A);
228
  cylp1 = ff + cylt1*ee;
229
  cylt2 = (-B + dscr)/(2*A);
230
  cylp2 = ff + cylt2*ee;
231
  if ( (cylp1 <= -1 && cylp2 <= -1)
232
       || (cylp1 >= 1 && cylp2 >= 1) ) {
233
    /* both intersections with infinite cylinder lie on ONE side of the
234
       finite extent, so there can't be an intersection */
235
    return AIR_FALSE;
236
  }
237
  /* else infinite ray DOES intersect finite cylinder; we have to find
238
     if any of the intersections are in the [neer, faar] interval */
239
  tidx = 0;
240
  if (AIR_IN_CL(-1, cylp1, 1)) {
241
    twot[tidx] = cylt1;
242
    twocap[tidx] = 0;
243
    tidx++;
244
  }
245
  if (AIR_IN_CL(-1, cylp2, 1)) {
246
    twot[tidx] = cylt2;
247
    twocap[tidx] = 0;
248
    tidx++;
249
  }
250
  if (tidx < 2) {
251
    /* at least one of the two intersections is with the endcaps */
252
    t = (-ff - 1)/ee;
253
    ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir);
254
    aa = pos[radi0]; bb = pos[radi1]; cc = aa*aa + bb*bb;
255
    if (cc <= 1) {
256
      twot[tidx] = t;
257
      twocap[tidx] = 1;
258
      tidx++;
259
    }
260
    if (tidx < 2) {
261
      /* try other endcap */
262
      t = (-ff + 1)/ee;
263
      ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir);
264
      aa = pos[radi0]; bb = pos[radi1]; cc = aa*aa + bb*bb;
265
      if (cc <= 1) {
266
        twot[tidx] = t;
267
        twocap[tidx] = 1;
268
        tidx++;
269
      }
270
    }
271
  }
272
  if (!tidx) {
273
    return AIR_FALSE;
274
  }
275
  if (2 == tidx && twot[0] > twot[1]) {
276
    ELL_SWAP2(twot[0], twot[1], aa);
277
    ELL_SWAP2(twocap[0], twocap[1], cap);
278
  }
279
  t = twot[0];
280
  cap = twocap[0];
281
  if (!AIR_IN_CL(ray->neer, t, ray->faar)) {
282
    if (1 == tidx) {
283
      return AIR_FALSE;
284
    }
285
    t = twot[1];
286
    cap = twocap[1];
287
    if (!AIR_IN_CL(ray->neer, t, ray->faar)) {
288
      return AIR_FALSE;
289
    }
290
  }
291
  /* else one of the intxs is in [neer,faar] segment */
292
  intx->t = t;
293
  ELL_3V_SCALE_ADD2(pos, 1, ray->from, t, ray->dir);
294
  switch(obj->axis) {
295
  case 0:
296
    ELL_3V_SET(intx->norm,     cap*pos[0], (1-cap)*pos[1], (1-cap)*pos[2]);
297
    break;
298
  case 1:
299
    ELL_3V_SET(intx->norm, (1-cap)*pos[0],     cap*pos[1], (1-cap)*pos[2]);
300
    break;
301
  case 2: default:
302
    ELL_3V_SET(intx->norm, (1-cap)*pos[0], (1-cap)*pos[1],     cap*pos[2]);
303
    break;
304
  }
305
  ELL_3V_NORM(intx->norm, intx->norm, tmp);
306
  intx->obj = OBJECT(obj);
307
  /* does NOT set u, v */
308
  return AIR_TRUE;
309
}
310
311
int
312
_echoRayIntx_Cube(RAYINTX_ARGS(Cube)) {
313
  echoPos_t t;
314
  int ax, dir;
315
316
  AIR_UNUSED(parm);
317
  if (!_echoRayIntx_CubeSurf(&t, &ax, &dir,
318
                             -1, 1,
319
                             -1, 1,
320
                             -1, 1, ray))
321
    return AIR_FALSE;
322
  intx->obj = (echoObject *)obj;
323
  intx->t = t;
324
  switch(ax) {
325
  case 0: ELL_3V_SET(intx->norm, dir, 0, 0); break;
326
  case 1: ELL_3V_SET(intx->norm, 0, dir, 0); break;
327
  case 2: ELL_3V_SET(intx->norm, 0, 0, dir); break;
328
  }
329
  intx->face = ax + 3*(dir + 1)/2;
330
  if (tstate->verbose) {
331
    fprintf(stderr, "%s%s: ax = %d --> norm = (%g,%g,%g)\n",
332
            _echoDot(tstate->depth), "_echoRayIntx_Cube", ax,
333
            intx->norm[0], intx->norm[1], intx->norm[2]);
334
  }
335
  /* does NOT set u, v */
336
  return AIR_TRUE;
337
}
338
339
void
340
_echoRayIntxUV_Cube(echoIntx *intx) {
341
  echoPos_t x, y, z;
342
343
  ELL_3V_GET(x, y, z, intx->pos);
344
  switch(intx->face) {
345
  case 0:
346
    intx->u = AIR_AFFINE(-1, y, 1, 0.0, 1.0);
347
    intx->v = AIR_AFFINE(-1, -z, 1, 0.0, 1.0);
348
    break;
349
  case 1:
350
    intx->u = AIR_AFFINE(-1, -x, 1, 0.0, 1.0);
351
    intx->v = AIR_AFFINE(-1, -z, 1, 0.0, 1.0);
352
    break;
353
  case 2:
354
    intx->u = AIR_AFFINE(-1, -x, 1, 0.0, 1.0);
355
    intx->v = AIR_AFFINE(-1, y, 1, 0.0, 1.0);
356
    break;
357
  case 3:
358
    intx->u = AIR_AFFINE(-1, -y, 1, 0.0, 1.0);
359
    intx->v = AIR_AFFINE(-1, z, 1, 0.0, 1.0);
360
    break;
361
  case 4:
362
    intx->u = AIR_AFFINE(-1, x, 1, 0.0, 1.0);
363
    intx->v = AIR_AFFINE(-1, z, 1, 0.0, 1.0);
364
    break;
365
  case 5:
366
    intx->u = AIR_AFFINE(-1, x, 1, 0.0, 1.0);
367
    intx->v = AIR_AFFINE(-1, -y, 1, 0.0, 1.0);
368
    break;
369
  }
370
}
371
372
/*
373
** TRI_INTX
374
**
375
** given a triangle in terms of origin, edge0, edge1, this will
376
** begin the intersection calculation:
377
** - sets pvec, tvec, qvec (all of them if intx is not ruled out )
378
** - sets u, and rules out intx based on (u < 0.0 || u > 1.0)
379
** - sets v, and rules out intx based on COND
380
** - sets t, and rules out intx based on (t < neer || t > faar)
381
*/
382
#define TRI_INTX(ray, origin, edge0, edge1, pvec, qvec, tvec,                \
383
                 det, t, u, v, COND, NOPE)                                   \
384
  ELL_3V_CROSS(pvec, ray->dir, edge1);                                       \
385
  det = ELL_3V_DOT(pvec, edge0);                                             \
386
  if (det > -ECHO_EPSILON && det < ECHO_EPSILON) {                           \
387
    NOPE;                                                                    \
388
  }                                                                          \
389
  /* now det is the reciprocal of the determinant */                         \
390
  det = 1.0/det;                                                             \
391
  ELL_3V_SUB(tvec, ray->from, origin);                                       \
392
  u = det * ELL_3V_DOT(pvec, tvec);                                          \
393
  if (u < 0.0 || u > 1.0) {                                                  \
394
    NOPE;                                                                    \
395
  }                                                                          \
396
  ELL_3V_CROSS(qvec, tvec, edge0);                                           \
397
  v = det * ELL_3V_DOT(qvec, ray->dir);                                      \
398
  if (COND) {                                                                \
399
    NOPE;                                                                    \
400
  }                                                                          \
401
  t = det * ELL_3V_DOT(qvec, edge1);                                         \
402
  if (t < ray->neer || t > ray->faar) {                                      \
403
    NOPE;                                                                    \
404
  }
405
406
int
407
_echoRayIntx_Rectangle(RAYINTX_ARGS(Rectangle)) {
408
  echoPos_t pvec[3], qvec[3], tvec[3], det, t, u, v, *edge0, *edge1, tmp;
409
410
  AIR_UNUSED(tstate);
411
  if (echoMatterLight == obj->matter
412
      && (ray->shadow || !parm->renderLights)) {
413
    return AIR_FALSE;
414
  }
415
  edge0 = obj->edge0;
416
  edge1 = obj->edge1;
417
  TRI_INTX(ray, obj->origin, edge0, edge1,
418
           pvec, qvec, tvec, det, t, u, v,
419
           (v < 0.0 || v > 1.0), return AIR_FALSE);
420
  intx->t = t;
421
  intx->u = u;
422
  intx->v = v;
423
  ELL_3V_CROSS(intx->norm, edge0, edge1);
424
  ELL_3V_NORM(intx->norm, intx->norm, tmp);
425
  intx->obj = OBJECT(obj);
426
  /* DOES set u, v */
427
  return AIR_TRUE;
428
}
429
430
int
431
_echoRayIntx_Triangle(RAYINTX_ARGS(Triangle)) {
432
  echoPos_t pvec[3], qvec[3], tvec[3], det, t, u, v, edge0[3], edge1[3], tmp;
433
434
  AIR_UNUSED(parm);
435
  AIR_UNUSED(tstate);
436
  ELL_3V_SUB(edge0, obj->vert[1], obj->vert[0]);
437
  ELL_3V_SUB(edge1, obj->vert[2], obj->vert[0]);
438
  TRI_INTX(ray, obj->vert[0], edge0, edge1,
439
           pvec, qvec, tvec, det, t, u, v,
440
            (v < 0.0 || u + v > 1.0), return AIR_FALSE);
441
  intx->t = t;
442
  intx->u = u;
443
  intx->v = v;
444
  ELL_3V_CROSS(intx->norm, edge0, edge1);
445
  ELL_3V_NORM(intx->norm, intx->norm, tmp);
446
  intx->obj = (echoObject *)obj;
447
  /* DOES set u, v */
448
  return AIR_TRUE;
449
}
450
451
int
452
_echoRayIntx_TriMesh(RAYINTX_ARGS(TriMesh)) {
453
  echoPos_t *pos, vert0[3], edge0[3], edge1[3], pvec[3], qvec[3], tvec[3],
454
    det, t, tmax, u, v, tmp;
455
  echoTriMesh *trim;
456
  int i, ret;
457
458
  AIR_UNUSED(parm);
459
  trim = TRIMESH(obj);
460
  if (!_echoRayIntx_CubeSolid(&t, &tmax,
461
                              trim->min[0], trim->max[0],
462
                              trim->min[1], trim->max[1],
463
                              trim->min[2], trim->max[2], ray)) {
464
    if (tstate->verbose) {
465
      fprintf(stderr, "%s%s: trimesh bbox (%g,%g,%g) --> (%g,%g,%g) not hit\n",
466
              _echoDot(tstate->depth), "_echoRayIntx_TriMesh",
467
              trim->min[0], trim->min[1], trim->min[2],
468
              trim->max[0], trim->max[1], trim->max[2]);
469
    }
470
    return AIR_FALSE;
471
  }
472
  /* stupid linear search for now */
473
  ret = AIR_FALSE;
474
  for (i=0; i<trim->numF; i++) {
475
    pos = trim->pos + 3*trim->vert[0 + 3*i];
476
    ELL_3V_COPY(vert0, pos);
477
    pos = trim->pos + 3*trim->vert[1 + 3*i];
478
    ELL_3V_SUB(edge0, pos, vert0);
479
    pos = trim->pos + 3*trim->vert[2 + 3*i];
480
    ELL_3V_SUB(edge1, pos, vert0);
481
    TRI_INTX(ray, vert0, edge0, edge1,
482
             pvec, qvec, tvec, det, t, u, v,
483
             (v < 0.0 || u + v > 1.0), continue);
484
    if (ray->shadow) {
485
      return AIR_TRUE;
486
    }
487
    intx->t = ray->faar = t;
488
    ELL_3V_CROSS(intx->norm, edge0, edge1);
489
    ELL_3V_NORM(intx->norm, intx->norm, tmp);
490
    intx->obj = (echoObject *)obj;
491
    intx->face = i;
492
    ret = AIR_TRUE;
493
  }
494
  /* does NOT set u, v */
495
  return ret;
496
}
497
498
void
499
_echoRayIntxUV_TriMesh(echoIntx *intx) {
500
  echoPos_t u, v, norm[3], len;
501
  echoTriMesh *trim;
502
503
  trim = TRIMESH(intx->obj);
504
  ELL_3V_SUB(norm, intx->pos, trim->meanvert);
505
  ELL_3V_NORM(norm, norm, len);
506
  if (norm[0] || norm[1]) {
507
    u = atan2(norm[1], norm[0]);
508
    intx->u = AIR_AFFINE(-AIR_PI, u, AIR_PI, 0.0, 1.0);
509
    v = -asin(norm[2]);
510
    intx->v = AIR_AFFINE(-AIR_PI/2, v, AIR_PI/2, 0.0, 1.0);
511
  }
512
  else {
513
    intx->u = 0;
514
    intx->v = AIR_AFFINE(1.0, norm[2], -1.0, 0.0, 1.0);
515
  }
516
}
517
518
int
519
_echoRayIntx_AABBox(RAYINTX_ARGS(AABBox)) {
520
  int ret;
521
  echoAABBox *box;
522
  echoPos_t t, tmax;
523
524
  box = AABBOX(obj);
525
  if (_echoRayIntx_CubeSolid(&t, &tmax,
526
                             box->min[0], box->max[0],
527
                             box->min[1], box->max[1],
528
                             box->min[2], box->max[2], ray)) {
529
    intx->boxhits++;
530
    ret = _echoRayIntx[box->obj->type](intx, ray, box->obj, parm, tstate);
531
  } else {
532
    ret = AIR_FALSE;
533
  }
534
  return ret;
535
}
536
537
int
538
_echoRayIntx_Split(RAYINTX_ARGS(Split)) {
539
  char me[]="_echoRayIntx_Split";
540
  echoObject *a, *b;
541
  echoPos_t *mina, *minb, *maxa, *maxb, t, tmax;
542
  int ret;
543
544
  if (ray->dir[obj->axis] > 0) {
545
    a = obj->obj0;
546
    mina = obj->min0;
547
    maxa = obj->max0;
548
    b = obj->obj1;
549
    minb = obj->min1;
550
    maxb = obj->max1;
551
  }
552
  else {
553
    a = obj->obj1;
554
    mina = obj->min1;
555
    maxa = obj->max1;
556
    b = obj->obj0;
557
    minb = obj->min0;
558
    maxb = obj->max0;
559
  }
560
561
  if (tstate->verbose) {
562
    fprintf(stderr, "%s%s: (shadow = %d):\n",
563
            _echoDot(tstate->depth), me, ray->shadow);
564
    fprintf(stderr, "%s%s: 1st: (%g,%g,%g) -- (%g,%g,%g) (obj %d)\n",
565
            _echoDot(tstate->depth), me,
566
            mina[0], mina[1], mina[2],
567
            maxa[0], maxa[1], maxa[2], a->type);
568
    fprintf(stderr, "%s%s: 2nd: (%g,%g,%g) -- (%g,%g,%g) (obj %d)\n",
569
            _echoDot(tstate->depth), me,
570
            minb[0], minb[1], minb[2],
571
            maxb[0], maxb[1], maxb[2], b->type);
572
  }
573
574
  ret = AIR_FALSE;
575
  if (_echoRayIntx_CubeSolid(&t, &tmax,
576
                             mina[0], maxa[0],
577
                             mina[1], maxa[1],
578
                             mina[2], maxa[2], ray)) {
579
    intx->boxhits++;
580
    if (_echoRayIntx[a->type](intx, ray, a, parm, tstate)) {
581
      if (ray->shadow) {
582
        return AIR_TRUE;
583
      }
584
      ray->faar = intx->t;
585
      ret = AIR_TRUE;
586
    }
587
  }
588
  if (_echoRayIntx_CubeSolid(&t, &tmax,
589
                             minb[0], maxb[0],
590
                             minb[1], maxb[1],
591
                             minb[2], maxb[2], ray)) {
592
    intx->boxhits++;
593
    if (_echoRayIntx[b->type](intx, ray, b, parm, tstate)) {
594
      ray->faar = intx->t;
595
      ret = AIR_TRUE;
596
    }
597
  }
598
  return ret;
599
}
600
601
int
602
_echoRayIntx_List(RAYINTX_ARGS(List)) {
603
  unsigned int i;
604
  int ret;
605
  echoObject *kid;
606
607
  ret = AIR_FALSE;
608
  for (i=0; i<obj->objArr->len; i++) {
609
    kid = obj->obj[i];
610
    if (_echoRayIntx[kid->type](intx, ray, kid, parm, tstate)) {
611
      ray->faar = intx->t;
612
      ret = AIR_TRUE;
613
      if (ray->shadow) {
614
        /* no point in testing any further */
615
        return ret;
616
      }
617
    }
618
  }
619
620
  return ret;
621
}
622
623
int
624
_echoRayIntx_Instance(RAYINTX_ARGS(Instance)) {
625
  echoPos_t a[4], b[4], tmp;
626
  echoRay iray;
627
628
  /*
629
  ELL_3V_COPY(iray.from, ray->from);
630
  ELL_3V_COPY(iray.dir, ray->dir);
631
  */
632
  ELL_4V_SET(a, ray->from[0], ray->from[1], ray->from[2], 1);
633
  ELL_4MV_MUL(b, obj->Mi, a);
634
  ELL_34V_HOMOG(iray.from, b);
635
  ELL_4V_SET(a, ray->dir[0], ray->dir[1], ray->dir[2], 0);
636
  ELL_4MV_MUL(b, obj->Mi, a);
637
  ELL_3V_COPY(iray.dir, b);
638
  if (tstate->verbose) {
639
    fprintf(stderr, "%s%s: dir (%g,%g,%g)\n%s   -- Mi --> "
640
            "(%g,%g,%g,%g)\n%s   --> (%g,%g,%g)\n",
641
            _echoDot(tstate->depth), "_echoRayIntx_Instance",
642
            a[0], a[1], a[2], _echoDot(tstate->depth),
643
            b[0], b[1], b[2], b[3], _echoDot(tstate->depth),
644
            iray.dir[0], iray.dir[1], iray.dir[2]);
645
  }
646
647
  iray.neer = ray->neer;
648
  iray.faar = ray->faar;
649
  iray.shadow = ray->shadow;
650
651
  if (_echoRayIntx[obj->obj->type](intx, &iray, obj->obj, parm, tstate)) {
652
    ELL_4V_SET(a, intx->norm[0], intx->norm[1], intx->norm[2], 0);
653
    ELL_4MV_TMUL(b, obj->Mi, a);
654
    ELL_3V_COPY(intx->norm, b);
655
    ELL_3V_NORM(intx->norm, intx->norm, tmp);
656
    if (tstate->verbose) {
657
      fprintf(stderr, "%s%s: hit a %d (at t=%g) with M == \n",
658
              _echoDot(tstate->depth), "_echoRayIntx_Instance",
659
              obj->obj->type, intx->t);
660
      ell_4m_PRINT(stderr, obj->M);
661
      fprintf(stderr, "%s   ... (det = %f), and Mi == \n",
662
              _echoDot(tstate->depth), ell_4m_DET(obj->M));
663
      ell_4m_PRINT(stderr, obj->Mi);
664
    }
665
    return AIR_TRUE;
666
  }
667
  /* else */
668
  return AIR_FALSE;
669
}
670
671
void
672
_echoRayIntxUV_Noop(echoIntx *intx) {
673
674
  AIR_UNUSED(intx);
675
}
676
677
/*
678
** NB: the intersections with real objects need to normalize
679
** intx->norm
680
*/
681
_echoRayIntx_t
682
_echoRayIntx[ECHO_TYPE_NUM] = {
683
  (_echoRayIntx_t)_echoRayIntx_Sphere,
684
  (_echoRayIntx_t)_echoRayIntx_Cylinder,
685
  (_echoRayIntx_t)_echoRayIntx_Superquad,
686
  (_echoRayIntx_t)_echoRayIntx_Cube,
687
  (_echoRayIntx_t)_echoRayIntx_Triangle,
688
  (_echoRayIntx_t)_echoRayIntx_Rectangle,
689
  (_echoRayIntx_t)_echoRayIntx_TriMesh,
690
  (_echoRayIntx_t)_echoRayIntx_Noop,
691
  (_echoRayIntx_t)_echoRayIntx_AABBox,
692
  (_echoRayIntx_t)_echoRayIntx_Split,
693
  (_echoRayIntx_t)_echoRayIntx_List,
694
  (_echoRayIntx_t)_echoRayIntx_Instance,
695
};
696
697
_echoRayIntxUV_t
698
_echoRayIntxUV[ECHO_TYPE_NUM] = {
699
  _echoRayIntxUV_Sphere,  /* echoTypeSphere */
700
  _echoRayIntxUV_Noop,    /* echoTypeCylinder */
701
  _echoRayIntxUV_Noop,    /* sqd.c: echoTypeSuperquad */
702
  _echoRayIntxUV_Cube,    /* echoTypeCube */
703
  _echoRayIntxUV_Noop,    /* echoTypeTriangle */
704
  _echoRayIntxUV_Noop,    /* echoTypeRectangle */
705
  _echoRayIntxUV_TriMesh, /* echoTypeTriMesh */
706
  _echoRayIntxUV_Noop,    /* echoTypeIsosurface */
707
  _echoRayIntxUV_Noop,    /* echoTypeAABBox */
708
  _echoRayIntxUV_Noop,    /* echoTypeSplit */
709
  _echoRayIntxUV_Noop,    /* echoTypeList */
710
  _echoRayIntxUV_Noop     /* echoTypeInstance */
711
};
712
713
int
714
echoRayIntx(echoIntx *intx, echoRay *ray, echoScene *scene,
715
            echoRTParm *parm, echoThreadState *tstate) {
716
  unsigned int idx;
717
  int ret;
718
  echoObject *kid;
719
  echoPos_t tmp;
720
721
  _echoVerbose = tstate->verbose;
722
723
  ret = AIR_FALSE;
724
  for (idx=0; idx<scene->rendArr->len; idx++) {
725
    kid = scene->rend[idx];
726
    if (_echoRayIntx[kid->type](intx, ray, kid, parm, tstate)) {
727
      ray->faar = intx->t;
728
      ret = AIR_TRUE;
729
      if (ray->shadow) {
730
        /* no point in testing any further */
731
        return ret;
732
      }
733
    }
734
  }
735
  if (ret) {
736
    /* being here means we're not a shadow ray */
737
    ELL_3V_SCALE_ADD2(intx->pos, 1, ray->from, intx->t, ray->dir);
738
    ELL_3V_SCALE(intx->view, -1, ray->dir);
739
    ELL_3V_NORM(intx->view, intx->view, tmp);
740
    /* this is needed for phong materials; for glass and metal,
741
       it is either used directly, or as a reference in fuzzification */
742
    _ECHO_REFLECT(intx->refl, intx->norm, intx->view, tmp);
743
  }
744
745
  return ret;
746
}