blob: a7292456b6da22f5a8551aa6555d603725dec3a3 [file] [log] [blame]
/*************************************************************************/
/* */
/* Copyright (c) 1994 Stanford University */
/* */
/* All rights reserved. */
/* */
/* Permission is given to use, copy, and modify this software for any */
/* non-commercial purpose as long as this copyright notice is not */
/* removed. All other uses, including redistribution in whole or in */
/* part, are forbidden without prior written permission. */
/* */
/* This software is provided with absolutely no warranty and no */
/* support. */
/* */
/*************************************************************************/
/*
* NAME
* geo.c
*
* DESCRIPTION
* This file contains routines that read both ascii and binary geometry
* files, as well as routines to normalize, print, and make a linked
* list of the geometry info.
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <math.h>
#include "rt.h"
/*
* Allocate and initialize sphere function pointer array.
*/
static PPROCS SphProcs =
{
SphName,
SphPrint,
SphRead,
NULL,
SphTransform,
SphIntersect,
SphPeIntersect,
SphNormal,
SphDataNormalize,
SphBoundBox
};
/*
* Allocate and initialize polygon function pointer array.
*/
static PPROCS PolyProcs =
{
PolyName,
PolyPrint,
PolyRead,
NULL,
PolyTransform,
PolyIntersect,
PolyPeIntersect,
PolyNormal,
PolyDataNormalize,
PolyBoundBox
};
/*
* Allocate and initialize triangle function pointer array.
*/
static PPROCS TriProcs =
{
TriName,
TriPrint,
TriRead,
NULL,
TriTransform,
TriIntersect,
TriPeIntersect,
TriNormal,
TriDataNormalize,
TriBoundBox
};
/*
* NAME
* MakeElementArray - make array of all primitive elements
*
* SYNOPSIS
* ELEMENT **MakeElementArray(totalElements)
* INT *totalElements;
*
* RETURNS
* Pointer to array of primitives.
*
*/
ELEMENT **MakeElementArray(totalElements)
INT *totalElements;
{
INT i;
OBJECT *po; /* Ptr to object. */
INT currArrayPosition = 0;
ELEMENT **npepa;
po = gm->modelroot;
*totalElements = 0;
while (po)
{
(*totalElements) += po->numelements;
po = po->next;
}
po = gm->modelroot;
npepa = ObjectMalloc(OT_PEPARRAY, *totalElements);
while (po)
{
for (i = 0; i < po->numelements; i++)
npepa[currArrayPosition++] = po->pelem + i;
po = po->next;
}
return (npepa);
}
/*
* NAME
* PrintGeo - print object geometry list
*
* SYNOPSIS
* VOID PrintGeo(po)
* OBJECT *po; // Ptr to object list to print.
*
* RETURNS
* Nothing.
*/
VOID PrintGeo(po)
OBJECT *po;
{
while (po)
{
fprintf(stdout, "Object %s\n", po->name);
fprintf(stdout, "\tcolor %f %f %f %f %f %f\n",
po->surf->fcolor[0], po->surf->fcolor[1],
po->surf->fcolor[2], po->surf->bcolor[0],
po->surf->bcolor[1], po->surf->bcolor[2]);
fprintf(stdout, "\tcoeffs %f %f %f %f %f\n",
po->surf->kdiff, po->surf->kspec, po->surf->ktran,
po->surf->refrindex, po->surf->kspecn);
(*po->procs->print)(po);
po = po->next;
}
}
/*
* NAME
* NormalizeGeo - normalize geometry to be within unit cube
*
* SYNOPSIS
* VOID NormalizeData(po, model, modelInvT)
* OBJECT *po; // Ptr to object list to normalize.
* MATRIX model; // Model matrix.
* MATRIX modelInvT; // Model inverse transpose.
*
* RETURNS
* Nothing.
*/
VOID NormalizeGeo(po, model, modelInvT)
OBJECT *po;
MATRIX model;
MATRIX modelInvT;
{
REAL norm_minx; /* Normalize min values. */
REAL norm_miny;
REAL norm_minz;
REAL norm_maxx; /* Normalize max values. */
REAL norm_maxy;
REAL norm_maxz;
REAL scale_min; /* Object min max values. */
REAL scale_max;
REAL scale; /* Normalization scale val. */
REAL trans; /* Normalization xlat val. */
OBJECT *poHead; /* Ptr to head of object list*/
MATRIX normMat; /* Normalization matrix. */
MATRIX tempMat; /* Temporary work matrix. */
poHead = po; /* Save ptr to head of list. */
if (! (TraversalType == TT_LIST && ModelNorm == FALSE) )
{
/* Find global bound box min/max. */
norm_minx = norm_miny = norm_minz = HUGE_REAL;
norm_maxx = norm_maxy = norm_maxz = -HUGE_REAL;
while (po)
{
norm_minx = Min(norm_minx, po->bv.dnear[0]);
norm_miny = Min(norm_miny, po->bv.dnear[1]);
norm_minz = Min(norm_minz, po->bv.dnear[2]);
norm_maxx = Max(norm_maxx, po->bv.dfar[0]);
norm_maxy = Max(norm_maxy, po->bv.dfar[1]);
norm_maxz = Max(norm_maxz, po->bv.dfar[2]);
po = po->next;
}
/* Compute scale factor. */
scale_min = Min(norm_minx, norm_miny);
scale_min = Min(scale_min, norm_minz);
scale_max = Max(norm_maxx, norm_maxy);
scale_max = Max(scale_max, norm_maxz);
scale = 1.0/(scale_max - scale_min);
trans = (-scale_min*scale);
Scale(tempMat, scale, scale, scale);
Translate(normMat, trans, trans, trans);
MatrixMult(normMat, tempMat, normMat);
/* Now, normalize object data. */
po = poHead;
while (po)
{
(*po->procs->normalize)(po, normMat);
po = po->next;
}
}
}
/*
* NAME
* ReadGeoFile - read in the geometry file
*
* SYNOPSIS
* VOID ReadGeoFile(GeoFileName)
* CHAR *GeoFileName; // File to open.
*
* DESCRIPTION
* Read in the model file - call primitive object routines to read in
* their own data. Objects are put in a linked list.
*
* Transform objects by modeling transformation if any.
*
* If TT_LIST traversal, ModelNorm parameter indicates whether data will
* be normalized.
*
* RETURNS
* Nothing.
*/
VOID ReadGeoFile(GeoFileName)
CHAR *GeoFileName;
{
INT i;
INT dummy;
INT stat; /* Input read counter. */
CHAR comchar;
CHAR primop; /* Primitive opcode. */
CHAR objstr[NAME_LEN]; /* Object descriptions. */
CHAR objname[NAME_LEN];
FILE *pf; /* Ptr to geo file desc. */
SURF *ps; /* Ptr to surface desc. */
MATRIX model; /* Model matrix. */
MATRIX modelInv; /* Model matrix inverse. */
MATRIX modelInvT; /* Model matrix inv transpose*/
OBJECT *po; /* Ptr to object. */
OBJECT *prev; /* Ptr to previous object. */
OBJECT *curr; /* Ptr to current object. */
ELEMENT *pe; /* Ptr to the element list. */
/* Open the model file. */
pf = fopen(GeoFileName, "r");
if (!pf)
{
printf("Unable to open model file %s.\n", GeoFileName);
exit(1);
}
/* Initialize pointers and counters. */
curr = NULL;
prev = NULL;
gm->modelroot = NULL;
prim_obj_cnt = 0;
prim_elem_cnt = 0;
/* Retrieve model transform. */
MatrixCopy(model, View.model);
MatrixInverse(modelInv, model);
MatrixTranspose(modelInvT, modelInv);
/* Check for comments. */
if ((comchar = getc(pf)) != '#')
ungetc(comchar, pf);
else
{
comchar = '\0'; /* Set to other than '#'. */
while (comchar != '#')
if ((comchar = getc(pf)) == EOF)
{
fprintf(stderr, "Incorrect comment in geometry file.\n");
exit(-1);
}
}
/* Process the file data for each object. */
while ((stat = fscanf(pf, "%s %s", objstr, objname)) != EOF)
{
if (stat != 2 || strcmp(objstr, "object") != 0)
{
printf("Invalid object definition %s.\n", objstr);
exit(-1);
}
/* Allocate next object and set list pointers. */
prim_obj_cnt++;
curr = GlobalMalloc(sizeof(OBJECT), "geo.c");
curr->index = prim_obj_cnt;
curr->next = NULL;
strcpy(curr->name, objname);
if (gm->modelroot == NULL)
gm->modelroot = curr;
else
prev->next = curr;
/* Get surface characteristics. */
ps = GlobalMalloc(sizeof(SURF), "geo.c");
curr->surf = ps;
stat = fscanf(pf, "%lf %lf %lf %lf %lf %lf",
&(ps->fcolor[0]), &(ps->fcolor[1]), &(ps->fcolor[2]),
&(ps->bcolor[0]), &(ps->bcolor[1]), &(ps->bcolor[2]));
if (stat != 6)
{
printf("Object color incorrect.\n");
exit(-1);
}
stat = fscanf(pf, "%lf %lf %lf %lf %lf",
&(ps->kdiff), &(ps->kspec), &(ps->ktran),
&(ps->refrindex), &(ps->kspecn));
if (stat != 5)
{
printf("Object surface coefficients incorrect.\n");
exit(-1);
}
/* Get texture and flag information. */
stat = fscanf(pf, "%ld %ld %ld %ld\n", &dummy, &dummy, &dummy, &dummy);
if (stat != 4)
{
printf("Texture and/or flag information not all present.\n");
exit(-1);
}
/* Get primitive opcode. */
stat = fscanf(pf, "%c %ld", &primop, &(curr->numelements));
if (stat != 2)
{
printf("Object primitive opcode.\n");
exit(-1);
}
switch (primop)
{
case 's':
curr->procs = &SphProcs;
break;
case 'p':
curr->procs = &PolyProcs;
break;
case 't':
curr->procs = &TriProcs;
break;
case 'c':
case 'q':
printf("Code for cylinders and quadrics not implemented yet.\n");
exit(-1);
default:
printf("Invalid primitive type \'%c\'.\n", primop);
exit(-1);
}
/* Allocate primitive elements and create indices. */
pe = GlobalMalloc(sizeof(ELEMENT)*curr->numelements, "geo.c");
curr->pelem = pe;
prim_elem_cnt += curr->numelements;
for (i = 1; i <= curr->numelements; i++, pe++)
pe->index = i;
/* Read, transform, and compute bounding box for object. */
(*curr->procs->read)(curr, pf);
(*curr->procs->transform)(curr, model, modelInvT);
(*curr->procs->bbox)(curr);
prev = curr;
}
NormalizeGeo(gm->modelroot, model, modelInvT);
fclose(pf);
}