This is surfshade.c in view mode; [Download] [Up]
/*
* surfshade.c
*
* Copyright (C) 1989, 1991, Craig E. Kolb
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
* $Id$
*
* $Log$
*/
#include "libobj/object.h"
#include "surface.h"
/*
* Compute surface properties from given hitlist
* Returns TRUE if ray is entering object, FALSE otherwise.
*/
int
ComputeSurfProps(hitlist, ray, pos, norm, gnorm, surf, smooth)
HitList *hitlist; /* Hit information (path through DAG) */
Ray *ray; /* Ray in world space */
Vector *pos; /* Intersection point */
Vector *norm, *gnorm; /* shading normal, geometric normal (return values) */
Surface *surf; /* Copy of surface to use (return value) */
int *smooth;
{
HitNode *hp;
int i;
Ray rtmp;
Object *prim, *obj;
Surface *stmp;
Float k, kp;
int texturing, transforming, entering;
Trans prim2model, world2model;
hp = hitlist->data;
prim = hp->obj;
/*
* Compute point of intersection in "primitive space".
*/
VecAddScaled(hp->ray.pos, hp->dist, hp->ray.dir, pos);
/*
* Find normal to primitive at point of intersection.
*/
*smooth = PrimNormal(prim, pos, norm, gnorm);
texturing = transforming = FALSE;
/*
* Walk down hit list, constructing world<-->primitive transformation
* and determining if we need to perform texture mapping.
* The last node is the World node, which cannot be textured or
* transformed, so we skip it.
*/
for (i = 0, hp = hitlist->data; i < hitlist->nodes -1; hp++, i++) {
obj = hp->obj;
if (obj->trans) {
/*
* Here we're actually computing prim2world.
* When finished, we invert it.
*/
if (transforming)
TransCompose(obj->trans, &world2model,
&world2model);
else
TransCopy(obj->trans, &world2model);
transforming = TRUE;
}
if (obj->texture)
texturing = TRUE;
}
/*
* Get surface to use via the application-provided function.
*/
stmp = GetShadingSurf(hitlist);
if (stmp == (Surface *)NULL)
RLerror(RL_PANIC, "GetShadingSurf returned NULL!\n");
/*
* Make a copy so it may be modified via texturing.
*/
*surf = *stmp;
/*
* Determine if we're entering or exiting the surface,
* flipping surface normals if necessary.
*/
k = dotp(&hitlist->data[0].ray.dir, norm);
if (*smooth) {
/*
* If gnorm and shading norm differ and
* their dot products with the ray have
* different signs, use the geometric normal
* instead, ala Snyder & Barr's paper.
*/
kp = dotp(&hitlist->data[0].ray.dir, gnorm);
if (k <= 0. && kp > 0. || k >= 0. && kp < 0.)
k = kp;
}
if (k > 0.) {
/* flip normals */
VecScale(-1., *gnorm, gnorm);
VecScale(-1., *norm, norm);
/*
* Normal indicates that we're exiting.
* Only set entering to TRUE if csg has indicated
* that the ray is, indeed, entering.
*/
entering = (hitlist->data[0].enter == ENTERING);
} else {
/*
* Normal indicates that we're entering.
* Set entering flag as such unless csg has
* told us that we're exiting.
*/
entering = !(hitlist->data[0].enter == EXITING);
}
/*
* If there are no transformations, then world2model is identity.
*/
if (!transforming)
TransInit(&world2model);
/*
* If we're not performing texturing, we simply need to compute
* the normal and point of intersection to world space.
*/
if (!texturing) {
/*
* At this point 'world2model' is really 'prim2world'.
*/
if (transforming) {
NormalTransform(norm, &world2model.itrans);
NormalTransform(gnorm, &world2model.itrans);
VecAddScaled(ray->pos,
hitlist->data[hitlist->nodes -1].dist,
ray->dir, pos);
}
return entering;
}
/*
* world2model currently transforms from primitive to world space.
* Invert it to get transformation from world to primitive space.
*/
TransInvert(&world2model, &world2model);
TransInit(&prim2model);
rtmp = hitlist->data[0].ray;
/*
* Walk down hitlist.
*/
for (hp = hitlist->data, i = 0; i < hitlist->nodes -1; i++, hp++) {
obj = hp->obj;
if (obj->trans) {
NormalTransform(norm, &obj->trans->itrans);
if (texturing) {
/*
* Compose prim<-->model and world<-->model
* with current transformation.
*/
TransCompose(obj->trans, &prim2model,
&prim2model);
TransCompose(obj->trans, &world2model,
&world2model);
/*
* Transform point and ray to model space.
*/
PointTransform(pos, &obj->trans->trans);
(void)RayTransform(&rtmp, &obj->trans->trans);
}
}
/*
* Apply textures
*/
if (obj->texture)
TextApply(obj->texture, prim, &rtmp, pos, norm,
gnorm, surf, &prim2model, &world2model);
}
return entering;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.