This is object.c in view mode; [Download] [Up]
/*
* object.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 "object.h"
#include "list.h"
Object *
ObjCreate(objptr, methods)
ObjRef objptr;
Methods *methods;
{
Object *obj;
if (objptr == (ObjRef)NULL)
return (Object *)NULL;
obj = (Object *)share_calloc(1, sizeof(Object));
obj->obj = objptr;
obj->methods = methods;
#ifdef SHAREDMEM
/*
* If the counter is in shared memory, processes will
* be modifying it left-and-right. So, we cheat and
* make counter a pointer to a non-shared location and
* store the value there.
*/
new->counter = (unsigned long *)Malloc(sizeof(unsigned long));
*new->counter = 0;
#endif
return obj;
}
/*
* Return a copy of the given object.
* Note that surface, texturing, and transformation information
* is copied by reference.
*/
Object *
ObjectCopy(obj)
Object *obj;
{
Object *new;
new = ObjCreate(obj->obj, obj->methods);
/* Share texturing, name, #prims, surface info */
new->name = obj->name;
new->texture = obj->texture;
new->surf = obj->surf;
new->prims = obj->prims;
new->trans = obj->trans;
/* copy bounds */
BoundsCopy(obj->bounds, new->bounds);
return new;
}
/*
* Report bounding box and number of primitives in object.
*/
void
AggregatePrintInfo(obj, fp)
Object *obj;
FILE *fp;
{
if (fp) {
fprintf(fp,"Object \"%s\":\n", obj->name);
BoundsPrint(obj->bounds, fp);
fprintf(fp,"\t%lu primitive%c\n",obj->prims,
obj->prims == 1 ? ' ' : 's');
}
}
/*
* Convert the given object from a linked list of objects to
* the desired aggregate type.
*/
int
AggregateConvert(obj, objlist)
Object *obj, *objlist;
{
if (!IsAggregate(obj)) {
RLerror(RL_ABORT, "A %s isn't an aggregate.\n",
ObjectName(obj));
return 0;
}
return (*obj->methods->convert)(obj->obj, objlist);
}
/*
* Set "bounds" of object to be the extent of the primitive.
*/
int
ObjectBounds(obj)
Object *obj;
{
if (obj && obj->methods->bounds) {
(*obj->methods->bounds) (obj->obj, obj->bounds);
} else {
RLerror(RL_ABORT, "Can't compute bounds of \"%s\".\n",
ObjectName(obj));
return FALSE;
}
/*
* Enlarge by EPSILON in each direction just to
* be on the safe side.
*/
obj->bounds[LOW][X] -= EPSILON;
obj->bounds[HIGH][X] += EPSILON;
obj->bounds[LOW][Y] -= EPSILON;
obj->bounds[HIGH][Y] += EPSILON;
obj->bounds[LOW][Z] -= EPSILON;
obj->bounds[HIGH][Z] += EPSILON;
return TRUE;
}
char *
ObjectName(obj)
Object *obj;
{
if (obj->methods->name)
return (*obj->methods->name)();
return "unknown";
}
void
ObjectStats(obj, tests, hits)
Object *obj;
unsigned long *tests, *hits;
{
if (obj && obj->methods->stats)
(*obj->methods->stats)(tests, hits);
else {
*tests = *hits = 0;
}
}
/*
* Push an object onto the head of the given stack, returning
* the new head.
*/
ObjList *
ObjStackPush(obj, list)
Object *obj;
ObjList *list;
{
ObjList *new;
/*
* Pretty simple.
* Make new element point to old head and return new head.
*/
new = (ObjList *)Malloc(sizeof(ObjList));
new->obj = obj;
new->next = list;
return new;
}
/*
* Pop the topmost object off of the given stack, returning the new head.
* The old head is freed, but the object it points to is not.
*/
ObjList *
ObjStackPop(list)
ObjList *list;
{
ObjList *ltmp;
ltmp = list->next; /* Save new head. */
free((voidstar)list); /* Free old head. */
return ltmp; /* Return new head. */
}
Methods *
MethodsCreate()
{
return (Methods *)share_calloc(1, sizeof(Methods));
}
/*
* Call appropriate routine to compute UV and, if non-null,
* dpdu and dpdv at given point on the given primitive. The
* normal is used to facilitate computation of u, v, and the
* partial derivatives.
*/
void
PrimUV(prim, pos, norm, uv, dpdu, dpdv)
Object *prim;
Vector *pos, *norm, *dpdu, *dpdv;
Vec2d *uv;
{
/*
* Call appropriate inverse mapping routine
*/
if (prim->methods->uv == NULL) {
uv->u = uv->v = 0.;
if (dpdu) {
dpdu->y = dpdu->z = 0.;
dpdu->x = 1.;
}
if (dpdv) {
dpdv->x = dpdv->z = 0.;
dpdv->y = 1.;
}
} else
(*prim->methods->uv)(prim->obj,pos,norm,uv,dpdu,dpdv);
}
int
PrimNormal(prim, pos, norm, gnorm)
Object *prim;
Vector *pos, *norm, *gnorm;
{
/*
* Call appropriate normal routine
*/
return (*prim->methods->normal) (prim->obj, pos, norm, gnorm);
}
int
PrimEnter(obj, ray, mind, hitd)
Object *obj;
Ray *ray;
Float mind, hitd;
{
/*
* Call appropriate enter/leave routine
*/
if (obj->methods->enter == NULL) {
Vector pos, nrm, gnrm;
/*
* Sleazy method: Use hit point, find normal
* and take dot prod with ray
*/
VecAddScaled(ray->pos, hitd, ray->dir, &pos);
PrimNormal(obj, &pos, &nrm, &gnrm);
return dotp(&ray->dir, &gnrm) < 0.0;
}
else
return (*obj->methods->enter) (obj->obj, ray, mind, hitd);
}
/*
* Walk through a linked-list of objects. If the object is unbounded,
* unlink it it from the list and add it to the 'unbounded' list.
* If the object is bounded, enlarge the given bounding box if
* necessary. Return pointer to unbounded list.
*/
Object *
BoundsFind(list, bounds, num)
Object **list;
Float bounds[2][3];
int *num;
{
Object *ltmp, *prev;
Object *unbounded, *nextobj;
BoundsInit(bounds);
prev = unbounded = (Object *)0;
*num = 0;
for (ltmp = *list; ltmp; ltmp = nextobj) {
nextobj = ltmp->next;
*num += ltmp->prims;
if (ltmp->bounds[LOW][X] > ltmp->bounds[HIGH][X]) {
/*
* Object is unbounded -- unlink it...
*/
if (prev)
prev->next = ltmp->next;
else
*list = ltmp->next;
/*
* And add it to unbounded object list.
*/
ltmp->next = unbounded;
unbounded = ltmp;
} else {
/*
* Object is bounded.
*/
BoundsEnlarge(bounds, ltmp->bounds);
prev = ltmp;
}
}
return unbounded;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.