home *** CD-ROM | disk | FTP | other *** search
- /*
- * objects.c -- standard object manipulations
- *
- * (c) 1993, 1994 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 <stdlib.h>
- #include "ray.h"
- #include "proto.h"
- #include "extern.h"
-
- PRIVATE
- boem()
- {
- assert(FALSE);
- }
-
- PRIVATE struct methods null_methods =
- {
- boem,
- boem,
- boem,
- boem,
- boem,
- boem,
- boem,
- boem,
- boem,
- boem,
- boem,
- "(none)",
- };
-
- /*
- * intersect a ray with an object.
- */
- PUBLIC bool
- intersect_object(dqueue * globalq, object *o, struct ray *r, int flags)
- {
- struct ray transray;
- bool b;
- bool hit;
- object *op;
-
- global_stats.objtest++;
-
- /* use speed in the ray. */
- transray = *r;
-
- svproduct(transray.pos, -Time, o->speed);
- vadd(transray.pos, r->pos, transray.pos);
-
- /* check for bounding shapes, walk them all */
- for (op = o->bound; op != NULL; op = op->next) {
- dqueue *q;
-
- if (op->methods->inside_method(o->bound, r->pos))
- continue;
-
- q = get_new_queue();
-
- /* Check bounding shape: */
- global_stats.boundtest++;
-
- /* don't translate bounds. */
- if (!intersect_object(q, op, r, FALSE)) {
- /* no intersection at all */
-
- free_queue(q);
- return FALSE;
- }
- /* found one! */
- if (!(flags & CHKALL) && q->t >= globalq->t) { /* close enough? */
- free_queue(q); /* no, exit */
- return FALSE;
- }
- free_queue(q);
-
- global_stats.boundhit++;/* And another bound has been succesful */
- }
-
- if (o->clip != NULL) {
-
- /* do clippingshape */
- dqueue *q,
- *qp;
- vector x;
-
- q = get_new_queue();
- o->methods->all_intersections_method(q, o, &transray, flags | CHKALL, &b);
-
- hit = FALSE;
- for (qp = q; (qp != NULL && qp->obj != NULL) && (flags & CHKALL ||
- !hit); qp = qp->next) {
- bool inside;
-
- /* find intersection point */
- svproduct(x, qp->t, transray.dir);
- vadd(x, transray.pos, x);
-
- global_stats.cliptest++;
-
- /*
- * filter out the intersections which are inside of the
- * clipping shape.
- */
- inside = TRUE;
- for (op = o->clip; op != NULL && inside; op = op->next) {
- if (!op->methods->inside_method(op, x))
- inside = FALSE;
- }
-
- if (inside) {
- add_to_queue(globalq, *qp);
- global_stats.cliphit++;
- hit = TRUE;
- }
- }
-
- free_queue(q);
- } else {
-
- /* intersect the ray with object's shape */
- hit = o->methods->all_intersections_method(globalq, o,
- &transray, flags, &b);
-
- }
- if (hit)
- global_stats.objhit++;
- return hit;
- }
-
- /* apply speed to one object */
- PUBLIC void
- speed_object(object *o, vector s)
- {
- if (o->type == COMPOSITE)
- speed_composite(o, s);
- else
- vadd(o->speed, s, o->speed);
- }
-
-
- /* append toadd to list starting with o. Both must have been allocated. */
- PUBLIC void
- append_to_object_list(object *o, object *toadd)
- {
- object *last;
-
- assert(o != NULL);
-
- for (; o != NULL; o = o->next)
- last = o;
- last->next = toadd;
- }
-
- /* add clipping shape from boundingshapes. */
- PUBLIC void
- add_bounds_to_clip(object *o)
- {
- object *srcp,
- *dstp;
-
- if (o->bound != NULL) { /* this object has a bound. */
- o->clip = get_new_object();
-
- dstp = o->clip;
-
- for (srcp = o->bound; srcp != NULL; srcp = srcp->next) {
-
- copy_object(dstp, srcp);
- if (srcp->next != NULL)
- dstp->next = get_new_object();
-
- dstp = dstp->next;
- }
- }
- }
-
-
- /* apply speed to a whole bunch of objects */
- PUBLIC void
- speed_object_list(object *start, vector s)
- {
- for (; start != NULL; start = start->next)
- speed_object(start, s);
- }
-
-
- /* standard routine */
- PUBLIC void
- copy_object(object *dst, object *src)
- {
- assert(dst != NULL && src != NULL);
-
- /* copy info */
- dst->type = NOSHAPE;
- dst->speed = src->speed;
- dst->inverted = src->inverted;
- dst->methods = src->methods;
- dst->next = NULL;
- dst->daddy = NULL;
-
- /* copy pointers */
- if (src->text != NULL) { /* check wether sources have a texture */
- if (dst->text == NULL) /* source has texture; does dest has space
- * for one? */
- dst->text = get_new_texture(); /* no, so alloc space */
- copy_texture(dst->text, src->text); /* now copy stuff */
- }
- /* copy the shape */
- src->methods->copy_method(dst, src);
-
- if (src->inv_trans) {
- dst->inv_trans = get_new_matrix();
- copy_matrix(*dst->inv_trans, *src->inv_trans);
- } {
- object *srcp,
- *dstp;
-
- if (src->bound != NULL) { /* this object has a bound. */
- dst->bound = get_new_object();
-
- for (dstp = dst->bound, srcp = src->bound; srcp != NULL; srcp = srcp->next) {
- copy_object(dstp, srcp);
- if (srcp->next != NULL)
- dstp->next = get_new_object();
- dstp = dstp->next;
- }
- }
- if (src->clip != NULL) {/* this object has a bound. */
- dst->clip = get_new_object();
-
- for (dstp = dst->clip, srcp = src->clip; srcp != NULL; srcp = srcp->next) {
- copy_object(dstp, srcp);
- if (srcp->next != NULL)
- dstp->next = get_new_object();
- dstp = dstp->next;
- }
- }
- }
-
- }
-
-
- PUBLIC void
- precompute_object(object *o)
- {
- object *op;
- vector displac;
-
- precompute_object_list(o->bound);
- precompute_object_list(o->clip);
- o->methods->precompute_method(o);
-
- if (o->bound != NULL)
- global_stats.bounds++;
- if (o->clip != NULL)
- global_stats.clips++;
- for (op = o->bound; op != NULL; op = op->next) {
- o->bmin.x = MAX(op->bmin.x, o->bmin.x);
- o->bmin.y = MAX(op->bmin.y, o->bmin.y);
- o->bmin.z = MAX(op->bmin.z, o->bmin.z);
- o->bmax.x = MIN(op->bmax.x, o->bmax.x);
- o->bmax.y = MIN(op->bmax.y, o->bmax.y);
- o->bmax.z = MIN(op->bmax.z, o->bmax.z);
- }
-
- vadd(o->bmax, o->bmax, fudge);
- vsub(o->bmin, o->bmin, fudge);
- global_stats.objects++;
- }
-
- PUBLIC void
- precompute_object_list(object *o)
- {
- for (; o != NULL; o = o->next)
- precompute_object(o);
- }
-
- /* initialize the object passed by p */
- PUBLIC void
- init_object(object *p)
- {
- /* initialize movement; pointers to NULL */
- setvector(p->speed, 0, 0, 0);
-
- /* set bmin and bmax to unity of min/max */
- setvector(p->bmin, INFTY, INFTY, INFTY);
- vneg(p->bmax, p->bmin);
-
- p->text = NULL;
- p->type = NOSHAPE;
- p->bound = NULL;
- p->clip = NULL;
- p->methods = &null_methods;
- p->daddy = NULL;
- p->next = NULL;
- p->inv_trans = NULL;
- p->inverted = FALSE;
- }
-
- /* alloc and init an object */
- PUBLIC object *
- get_new_object(void)
- {
- object *p;
-
- p = ALLOC(object);
-
- CHECK_MEM(p, "object");
- init_object(p);
- return p;
- }
-
- /* std routine: rotate an object */
- PUBLIC void
- rotate_object(object *op, matrix rotmat)
- {
- if (op->text != NULL)
- rotate_texture(op->text, rotmat);
-
- op->methods->rotate_method(op, rotmat);
-
- rotate_vector(&op->speed, rotmat);
-
- if (op->bound != NULL)
- rotate_object(op->bound, rotmat);
- if (op->clip != NULL)
- rotate_object(op->clip, rotmat);
-
- }
-
- /* translate an object */
- PUBLIC void
- translate_object(object *op, vector t)
- {
- if (op->text != NULL)
- translate_texture(op->text, t);
-
- op->methods->translate_method(op, t);
-
- if (op->bound != NULL)
- translate_object(op->bound, t);
- if (op->clip != NULL)
- translate_object(op->clip, t);
- }
-
- /* and scale it */
- PUBLIC void
- scale_object(object *op, vector s)
- {
- op->methods->scale_method(op, s);
-
- if (op->text != NULL)
- scale_texture(op->text, s);
-
- vcproduct(op->speed, op->speed, s);
-
- if (op->bound != NULL)
- scale_object(op->bound, s);
- if (op->clip != NULL)
- scale_object(op->clip, s);
- }
-
-
- PUBLIC void
- generic_scale_object(object *o, vector s)
- {
- matrix m;
-
- if (o->inv_trans == NULL)
- o->inv_trans = get_new_matrix();
- inv_scale_matrix(m, s);
- mmproduct(*o->inv_trans, *o->inv_trans, m);
- }
-
- PUBLIC void
- generic_translate_object(object *o, vector t)
- {
- matrix m;
-
- if (o->inv_trans == NULL)
- o->inv_trans = get_new_matrix();
-
- inv_translate_matrix(m, t);
- mmproduct(*o->inv_trans, *o->inv_trans, m);
- }
-
- PUBLIC void
- generic_rotate_object(object *o, matrix m)
- {
- matrix r;
-
- if (o->inv_trans == NULL)
- o->inv_trans = get_new_matrix();
- transpose_matrix(r, m);
- mmproduct(*o->inv_trans, *o->inv_trans, r);
- }
-
- /* give back memory used by an object */
- PUBLIC void
- free_object(object *op)
- {
- if (op->text != NULL)
- free_texture(op->text);
- op->methods->free_method(op);
- if (op->bound != NULL)
- free_object_list(op->bound);
- if (op->clip != NULL)
- free_object_list(op->clip);
- if (op->inv_trans != NULL)
- free(op->inv_trans);
-
- free((void *) op);
- }
-
- /* zap a list of objects */
- PUBLIC void
- free_object_list(object *p)
- {
- object *next;
-
- for (; p != NULL; p = next) {
- next = p->next;
- free_object(p);
- }
- }
-
- /* rotation */
- PUBLIC void
- rotate_object_list(object *p, matrix rotmat)
- {
- for (; p != NULL; p = p->next)
- rotate_object(p, rotmat);
- }
-
- /* scaling */
- PUBLIC void
- scale_object_list(object *p, vector r)
- {
- for (; p != NULL; p = p->next)
- scale_object(p, r);
- }
-
- /* translation */
- PUBLIC void
- translate_object_list(object *p, vector r)
- {
- for (; p != NULL; p = p->next)
- translate_object(p, r);
- }
-
-
- PUBLIC void
- print_object(object *obj)
- {
- #ifdef DEBUG
- printf("(");
- if (obj->bound != NULL) {
- printf("{ BOUNDINGSHAPES:");
- print_object_list(obj->bound);
- printf("}");
- }
- printf("BBOX:\n");
- print_v(" bound_min", obj->bmin);
- print_v(" bound_max", obj->bmax);
-
- if (obj->clip != NULL) {
- printf("{ CLIPPINGSHAPES:");
- print_object_list(obj->clip);
- printf("}");
- }
- if (obj->inv_trans != NULL) {
- printf("Inverse Transformation\n");
- print_matrix(*obj->inv_trans);
- }
- printf("shape type %d, %s%s\n", obj->type, (obj->inverted) ? "inverted " : "", obj->methods->name);
-
- obj->methods->print_method(obj);
-
- if (obj->text != NULL)
- print_texture(obj->text);
- print_v("speed", obj->speed);
- printf(")\n\n");
- #endif
- }
-
- PUBLIC void
- print_object_list(object *o)
- {
- #ifdef DEBUG
- for (; o != NULL; o = o->next)
- print_object(o);
- #endif
- }
-