home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * Copyright (c) 1987, David B. Wecker *
- * All Rights Reserved *
- * *
- * This file is part of DBW_Render *
- * *
- * DBW_Render is distributed in the hope that it will be useful, but *
- * WITHOUT ANY WARRANTY. No author or distributor accepts *
- * responsibility to anyone for the consequences of using it or for *
- * whether it serves any particular purpose or works at all, unless *
- * he says so in writing. Refer to the DBW_Render General Public *
- * License for full details. *
- * *
- * Everyone is granted permission to copy, modify and redistribute *
- * DBW_Render, but only under the conditions described in the *
- * DBW_Render General Public License. A copy of this license is *
- * supposed to have been given to you along with DBW_Render so you *
- * can know your rights and responsibilities. It should be in a file *
- * named COPYING. Among other things, the copyright notice and this *
- * notice must be preserved on all copies. *
- ************************************************************************
- * *
- * Authors: *
- * DBW - David B. Wecker *
- * *
- * Versions: *
- * V1.0 870125 DBW - First released version *
- * *
- ************************************************************************/
-
- /* INT.C - calculations for ray intersections with primitives */
-
- #define MODULE_INTER
- #include "ray.h"
-
- node *get_next_intersection(which,best_p,best_t)
- int which;
- vector best_p;
- float *best_t;
- {
- /* This routine returns the pertinent data for the i'th intersection */
-
- if (which >= g_objcounter)
- return NULL; /* No more intersections */
- else
- {
- *best_t = g_distances[which];
- veccopy(g_points[which],best_p);
- return g_objpairs[which];
- }
- }
-
-
- void add_intersection(np,p,t,attenuating)
- node *np;
- vector p;
- float t;
- int attenuating;
- {
- int add;
-
- /*
- * This routine adds the passed intersection information to the global list
- * of intersections. As a performance optimization,if we know that all
- * objects are opaque,then rather than accumulating the entire list and
- * sorting it later,we merely keep track of the closest intersection.
- */
- add = FALSE;
-
- if ( allopaque == 0 || /* Some transparency, all everything */
- g_objcounter == 0 || /* First opaque intersection */
- t < g_distances[0])
- {
- add = TRUE; /* Nearer opaque intersection */
- }
-
- if ( attenuating &&
- np->attr.tra[0] >= .99 &&
- np->attr.tra[1] >= .99 &&
- np->attr.tra[2] >= .99)
- {
- add = FALSE; /* ignore invisible objects when doing shadows */
- }
-
- if (add)
- {
- g_distances[g_objcounter] = t;
- veccopy(p,g_points[g_objcounter]);
- g_objpairs[g_objcounter] = np;
- if (g_objcounter < MAXOBJ)
- g_objcounter++;
- }
- }
-
- void calc_intersections(np,eye,d,attenuating)
- node *np; /* current node */
- vector d; /* direction vector for current ray */
- vector eye; /* current ray origin (eye point) */
- int attenuating; /* attenuation factor for each hit */
- {
-
- /*
- * This routine calculates the intersection of a ray with a given object.
- * If an intersection is found,the appropriate parameters are added to a
- * global list. This routine is recursive,to handle nested extents.
- */
-
- vector p;
- float t;
- int hit;
- long curs;
-
- /* keep track of maximum stack extent */
- curs = curstack();
- if (curs < stackbot)
- stackbot = curs;
-
- while (np)
- {
- hit = FALSE;
- switch (np->kind)
- {
- case EXTENT :
- if (hitsphere(eptr(np)->center,eptr(np)->radius,eye,d,p,&t))
- calc_intersections(eptr(np)->sub,eye,d,attenuating);
- break;
-
- case SPHERE :
- hit = hitsphere(sptr(np)->center,sptr(np)->radius,eye,d,p,&t);
- break;
-
- case TRIANGLE :
- hit = hittriangle(np,eye,d,p,&t);
- break;
-
- case QUAD :
- hit = hitquad(np,eye,d,p,&t);
- break;
-
- case RING :
- hit = hitring(np,eye,d,p,&t);
- break;
-
- case CYLINDER :
- hit = hitcylinder(np,eye,d,p,&t);
- break;
-
- default :
- hit = FALSE;
- break;
- }
-
- if (hit)
- add_intersection(np,p,t,attenuating); /* Add to global list */
-
- np = np->next; /* On to the next object */
- }
- }
-
- void all_intersects(eye,d,attenuating)
- vector d;
- vector eye;
- int attenuating;
- {
-
- /*
- * This routine computes all of the ray-object intersections that occur for
- * the specified ray. The intersections are stored in global arrays, sorted
- * closest intersection to furthest.
- */
-
- g_objcounter = 0; /* Clear the intersection list */
-
- calc_intersections(root,eye,d,attenuating); /* Find them & add to list */
-
- if (g_objcounter > 1)
- shell(g_distances,g_points,g_objpairs,g_objcounter); /* Sort them */
-
- /* Keep statistics (and decide when to GIVE UP!!) */
- if (++curr_runs >= max_runs)
- longjmp(env,-1);
-
- if (g_objcounter > max_intersects)
- max_intersects = g_objcounter;
- }
-
- int bouncelighting(pseudointensity,pseudolitdir,bouncenp,lit)
- vector pseudointensity,
- pseudolitdir;
- node *bouncenp;
- int lit;
- {
- vector n,bouncepoint,lightdir;
-
- if (bouncenp->kind == SPHERE || bouncenp->attr.ref == 0.0)
- return FALSE; /* No pseudo light source from here */
- else
- {
- switch (bouncenp->kind)
- {
- case TRIANGLE :
- veccopy(tptr(bouncenp)->position,bouncepoint);
- break;
- case QUAD :
- veccopy(qptr(bouncenp)->position,bouncepoint);
- break;
- case RING :
- veccopy(rptr(bouncenp)->position,bouncepoint);
- break;
- }
- findnormal(bouncenp,bouncepoint,n);
- veccopy(light[lit].direction,lightdir); /* Assume directional light */
- if (light[lit].kind != 0)
- { /* Point source */
- DIRECTION(bouncepoint,lightdir,lightdir);
- }
-
- vecscale(2.0 * DOT(lightdir,n),n,pseudolitdir);
- vecsub(lightdir,pseudolitdir,pseudolitdir);
- vecscale(bouncenp->attr.ref,light[lit].intensity,pseudointensity);
- return TRUE;
- }
- }
-
- void blendcolor(original,target,scale,result)
- vector original;
- vector target;
- vector result;
- float scale;
- {
- vector path;
-
- if (scale < 0.0)
- scale = 0.0; /* clip off excessive blending */
- if (scale > 1.0)
- scale = 1.0;
- vecsub(target,original,path);
- vecscale(scale,path,path);
- vecsum(original,path,result);
- }
-
- void getatten(atten,p,d,lit,pointdist)
- vector atten;
- vector p;
- vector d;
- int lit;
- float pointdist;
- {
- vector best_p;
- float best_t;
- int hitnext;
-
- #ifdef MCH_AMIGA
- node *occlude = 1L;
- #else
- node *occlude = (node *)1L;
- #endif
-
- atten[0] = 1.0; /* assume no attenuation */
- atten[1] = 1.0;
- atten[2] = 1.0;
- hitnext = 0;
- all_intersects(p,d,1); /* Compute all intersections */
-
- while (occlude && (atten[0] > 0.01 || atten[1] > 0.01 || atten[2] > 0.01))
- if (occlude = get_next_intersection(hitnext,best_p,&best_t))
- {
- if (light[lit].kind == 0 || best_t <= pointdist)
- {
- vecmul(atten,occlude->attr.tra,atten);
- }
- hitnext++;
- }
- }