home *** CD-ROM | disk | FTP | other *** search
- /*
- * disc.c -- handle disc type objects This is what an object-file should
- * look like.
- *
- * (c) 1993, 1994 by Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include "ray.h"
- #include "proto.h"
- #include "extern.h"
-
- extern struct methods my_methods;
-
- /* zap memory used by o->data.disc, and its substructures */
- PRIVATE void
- free_disc(object *o)
- {
- free((void *) o->data.disc);
- o->type = NOSHAPE;
- }
-
- /* initialize a disc_data struct */
- PRIVATE void
- init_disc(struct disc_data *t)
- {
- setvector(t->n, 0, 0, 0);
- setvector(t->center, 0, 0, 0);
- t->R = 1;
- t->r = -1;
- }
-
- PRIVATE struct disc_data *
- get_new_disc(void)
- {
- struct disc_data *p;
-
- p = ALLOC(struct disc_data);
-
- CHECK_MEM(p, my_methods.name);
- init_disc(p);
- return p;
- }
-
- PRIVATE bool
- inside_disc(object *o, vector i)
- {
- assert(FALSE);
- }
-
- /* scale it. */
- PRIVATE void
- scale_disc(object *o, vector s)
- {
- struct disc_data *t = o->data.disc;
- double factor;
-
- if (ABS(s.x) != ABS(s.y) || ABS(s.y) != ABS(s.z)) {
- generic_scale_object(o, s);
- } else {
- t->n.x = t->n.x / s.x;
- t->n.y = t->n.y / s.y;
- t->n.z = t->n.z / s.z;
-
- factor = MAX(ABS(s.x), ABS(s.y));
- factor = MAX(factor, ABS(s.z));
-
- t->R *= factor;
- t->r *= factor;
-
- vcproduct(t->center, t->center, s);
- }
- }
-
- /* rotation */
- PRIVATE void
- rotate_disc(object *o, matrix rotmat)
- {
- struct disc_data *b = o->data.disc;
-
- if (o->inv_trans)
- generic_rotate_object(o, rotmat);
- else {
- rotate_vector(&b->n, rotmat);
- rotate_vector(&b->center, rotmat);
- }
- }
-
- /* and translation */
- PRIVATE void
- translate_disc(object *o, vector t)
- {
- struct disc_data *b;
-
- if (o->inv_trans)
- generic_translate_object(o, t);
- else {
-
-
- b = o->data.disc;
- vadd(b->center, b->center, t);
- }
- }
-
- PUBLIC void
- print_disc(object *o)
- {
- #ifdef DEBUG
- struct disc_data *p = o->data.disc;
-
- print_v("normal", p->n);
- print_v("center", p->center);
- printf("R %f r %f\n", p->R, p->r);
- #endif
- }
-
- /*
- * intersect with the o->data.disc part, return TRUE if intersection
- * found.
- */
- PRIVATE bool
- all_disc_intersections(dqueue * q, object *o, struct ray *input, int flags, bool *isinside)
- {
- dqueue q_ent;
-
- struct disc_data *d = o->data.disc;
- double t,
- dot;
- vector x;
- double l;
- struct ray *r,
- localray;
-
- if (o->inv_trans) {
- localray = *input;
- r = &localray;
- transform_ray(r, o);
- } else
- r = input;
-
-
- my_methods.test++;
-
- /* do a plane intersection */
- dot = vdot(r->dir, d->n);
-
- if (ISZERO(dot))
- return FALSE;
-
- t = (d->mov - vdot(r->pos, d->n)) / dot;
- if (t < tolerance || t > r->maxt)
- return FALSE;
-
- /* find distance to center */
- svproduct(x, t, r->dir);
- vadd(x, x, r->pos);
- vsub(x, x, d->center);
-
- l = veclen(x);
-
- /* inside? */
- if (l < d->R && l > d->r) {
- my_methods.hit++;
- q_ent.obj = o;
- q_ent.t = t;
- add_to_queue(q, q_ent);
- return TRUE;
- } else
- return FALSE;
- }
-
- /*
- * returns the normal to the disc
- */
- PRIVATE vector
- disc_normal(struct intersect i, vector loc)
- {
- object *o = i.q_ent.obj;
- struct disc_data *p = o->data.disc;
-
- if (o->inv_trans) {
- vector n;
-
- n = transform_normal(*o->inv_trans, p->n);
- norm(n, n);
- return n;
- } else
- return p->n;
- }
-
- /* copy the shape data */
- PRIVATE void
- copy_disc(object *dst, object *src)
- {
- assert(dst != NULL && src != NULL);
-
- if (dst->type != DISC)
- dst->data.disc = get_new_disc();
- *dst->data.disc = *src->data.disc;
- dst->type = src->type;
- }
-
- /*
- * bound a disc. It's the same routine as the torus, except, the the minor
- * radius is set to zero.
- */
- PRIVATE void
- precompute_disc(object *o)
- {
- struct disc_data *t = o->data.disc;
-
- double min[3],
- max[3]; /* returned minimum and maximum of extent */
- matrix ctm,
- tempmatrix; /* cumulative transformation matrix */
- double r; /* major radius of torus */
- int i;
- double u1,
- u2,
- v1,
- v2,
- tmp,
- denominator;
-
-
- /* precomputation */
- t->mov = vdot(t->n, t->center);
-
- /* do bounding */
- r = t->R;
-
- {
- double theta,
- phi;
- vector rot;
-
- theta = acos(t->n.y / veclen(t->n));
- phi = safe_arctangent(t->n.z, t->n.x);
-
- setvector(rot, 0, 0, -theta);
- rotate_matrix(ctm, rot);
-
- setvector(rot, 0, -phi, 0);
- rotate_matrix(tempmatrix, rot);
- mmproduct(ctm, tempmatrix, ctm);
- }
-
- translate_matrix(tempmatrix, t->center);
- mmproduct(ctm, tempmatrix, ctm);
-
- if (o->inv_trans) {
- invert_trans(tempmatrix, *o->inv_trans);
- mmproduct(tempmatrix, tempmatrix, ctm);
-
- /* Gems do everything transposed. */
- transpose_matrix(ctm, tempmatrix);
- }
- for (i = 0; i < 3; i++) {
-
- /* calculate first extremum. assure that -PI/2 <= v1 <= PI/2 */
- u1 = safe_arctangent(ctm[2][i], ctm[0][i]);
- denominator = ctm[0][i] * cos(u1) + ctm[2][i] * sin(u1);
- v1 = safe_arctangent(ctm[1][i], denominator);
-
- /* second extremum is +/- PI from u1, negative of v1 */
- if (u1 <= 0)
- u2 = u1 + M_PI;
- else
- u2 = u1 - M_PI;
- v2 = -v1;
-
- /* find and sort extrema locations in this dimension */
- min[i] =
- ctm[0][i] * cos(u1) * (r) +
-
- ctm[2][i] * sin(u1) * (r) +
- ctm[3][i];
- max[i] =
- ctm[0][i] * cos(u2) * (r) +
-
- ctm[2][i] * sin(u2) * (r) +
- ctm[3][i];
- if (min[i] > max[i]) {
- tmp = max[i];
- max[i] = min[i];
- min[i] = tmp;
- }
- }
-
- o->bmin.x = min[0];
- o->bmin.y = min[1];
- o->bmin.z = min[2];
- o->bmax.x = max[0];
- o->bmax.y = max[1];
- o->bmax.z = max[2];
-
- my_methods.howmuch++;
- global_stats.prims++;
-
- }
-
- /* below, nothings has to be changed. */
- PRIVATE struct methods my_methods =
- {
- all_disc_intersections,
- disc_normal,
- copy_disc,
- inside_disc,
- rotate_disc,
- translate_disc,
- scale_disc,
- free_disc,
- print_disc,
- precompute_disc,
- "disc",
- };
-
- /* alloc/init */
- PUBLIC object *
- get_new_disc_object(void)
- {
- object *o;
-
- o = get_new_object();
-
- o->data.disc = get_new_disc();
-
- o->methods = &my_methods;
- o->type = DISC;
-
- return o;
- }
-
- /* eof */
-