cnsy@vax5.CIT.CORNELL.EDU (05/31/89)
Here's the Neutral File Format file viewer that doesn't need sbdl (Starbase
Display List) software. It's called "lookonce", since it's not interactive.
If you want more databases, check pub/nff in skinner.cs.uoregon.edu, via
anonymous ftp.
Enjoy,
Eric Haines hpfcla!hpfcrs!eye!erich@hplabs.hp.com
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Eric Haines <erich@juniper> on Thu May 25 14:04:41 1989
#
# This archive contains:
# README def.h lib.c lib.h
# lookat.c lookonce.c makefile pol005.nff
# pol006.nff tetra.nff
#
LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH
echo x - README
cat >README <<'@EOF'
Lookat
------
Needs sbdl (Starbase Display List) library to run.
unpack, cd into the new "SPD" directory, "make",
then type "lookat tetra.nff" for a mouse controlled view.
Define OUTDEV, OUTDRIVER, INDEV and INDRIVER if another
device than the SRX and the mouse is desired.
These are the assumed defaults for each program:
INDEV=/dev/hil2
INDRIVER=hp-hil
OUTDEV=/dev/crt
OUTDRIVER=hp98721
Lookonce
--------
unpack, cd into the new "SPD" directory, "make",
then type "lookonce tetra.nff" for a single view.
Define OUTDEV, OUTDRIVER if another device than the SRX is desired.
These are the assumed defaults for each program:
OUTDEV=/dev/crt
OUTDRIVER=hp98721
@EOF
chmod 644 README
echo x - def.h
cat >def.h <<'@EOF'
/*
* def.h contains some useful definitions for "C" programs.
*
* Version: 2.2 (11/17/87)
* Author: Eric Haines, 3D/Eye, Inc.
*/
#define EPSILON 5.0e-6
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef PI
#define PI 3.141592653589793
#endif
typedef double MATRIX[4][4] ; /* row major form */
typedef struct {
double x ;
double y ;
double z ;
double w ;
} COORD4, *COORD4_P ;
#define ABSOLUTE(A) ( (A) < 0 ? -(A) : (A) )
#define FRACTION(A) ( (A) - (long)(A) )
#define MAX(A,B) ( (A) > (B) ? (A) : (B) )
#define MAX3(A,B,C) ( MAX( MAX( A,B ), C ) )
#define MIN(A,B) ( (A) < (B) ? (A) : (B) )
#define MIN3(A,B,C) ( MIN( MIN( A,B ), C ) )
#define SQR(A) ( (A) * (A) )
#define ADD2_COORD(r,a) { (r).x += (a).x; (r).y += (a).y;\
(r).z += (a).z; }
#define ADD3_COORD(r,a,b) { (r).x = (a).x + (b).x;\
(r).y = (a).y + (b).y;\
(r).z = (a).z + (b).z; }
#define COPY_COORD(r,a) { (r).x = (a).x; (r).y = (a).y; (r).z = (a).z;}
#define COPY_COORD4(r,a) { (r).x = (a).x; (r).y = (a).y; (r).z = (a).z;\
(r).w = (a).w; }
#define CROSS(r,a,b) { (r).x = (a).y * (b).z - (a).z * (b).y;\
(r).y = (a).z * (b).x - (a).x * (b).z;\
(r).z = (a).x * (b).y - (a).y * (b).x; }
#define DOT_PRODUCT(a,b) ( (a).x * (b).x +\
(a).y * (b).y +\
(a).z * (b).z )
#define SET_COORD(r,a,b,c) { (r).x = (a); (r).y = (b); (r).z = (c); }
#define SET_COORD4(r,a,b,c,d) { (r).x = (a); (r).y = (b); (r).z = (c);\
(r).w = (d); }
#define SUB2_COORD(r,a) { (r).x -= (a).x; (r).y -= (a).y;\
(r).z -= (a).z; }
#define SUB3_COORD(r,a,b) { (r).x = (a).x - (b).x;\
(r).y = (a).y - (b).y;\
(r).z = (a).z - (b).z; }
@EOF
chmod 640 def.h
echo x - lib.c
cat >lib.c <<'@EOF'
/*
* lib.c - a library of vector operations, a random number generator, and
* object output routines.
*
* Version: 2.2 (11/17/87)
* Author: Eric Haines, 3D/Eye, Inc.
*/
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include "def.h"
#include "lib.h"
/*
* Normalize the vector (X,Y,Z) so that X*X + Y*Y + Z*Z = 1.
*
* The normalization divisor is returned. If the divisor is zero, no
* normalization occurs.
*
*/
double lib_normalize_coord3( cvec )
COORD4 *cvec;
{
double divisor;
divisor = sqrt( (double)DOT_PRODUCT( (*cvec), (*cvec) ) ) ;
if ( divisor != 0.0 ) {
cvec->x /= divisor;
cvec->y /= divisor;
cvec->z /= divisor;
}
return( divisor );
}
/*
* Set all matrix elements to zero.
*/
lib_zero_matrix( mx )
MATRIX mx ;
{
long i, j ;
for ( i = 0 ; i < 4 ; ++i ) {
for ( j = 0 ; j < 4 ; ++j ) {
mx[i][j] = 0.0 ;
}
}
}
/*
* Create identity matrix.
*/
lib_create_identity_matrix( mx )
MATRIX mx ;
{
long i ;
lib_zero_matrix( mx ) ;
for ( i = 0 ; i < 4 ; ++i ) {
mx[i][i] = 1.0 ;
}
}
/*
* Create a rotation matrix along the given axis by the given angle in radians.
*/
lib_create_rotate_matrix( mx, axis, angle )
MATRIX mx ;
long axis ;
double angle ;
{
double cosine ;
double sine ;
lib_zero_matrix( mx ) ;
cosine = cos( (double)angle ) ;
sine = sin( (double)angle ) ;
switch ( axis ) {
case X_AXIS:
mx[0][0] = 1.0 ;
mx[1][1] = mx[2][2] = cosine ;
mx[1][2] = sine ;
mx[2][1] = -sine ;
break ;
case Y_AXIS:
mx[1][1] = 1.0 ;
mx[0][0] = mx[2][2] = cosine ;
mx[2][0] = sine ;
mx[0][2] = -sine ;
break ;
case Z_AXIS:
mx[2][2] = 1.0 ;
mx[0][0] = mx[1][1] = cosine ;
mx[0][1] = sine ;
mx[1][0] = -sine ;
break ;
}
mx[3][3] = 1.0 ;
}
/*
* Create a rotation matrix along the given axis by the given angle in radians.
* The axis is a set of direction cosines.
*/
lib_create_axis_rotate_matrix( mx, rvec, angle )
MATRIX mx ;
COORD4 *rvec ;
double angle ;
{
COORD4 axis ;
double cosine ;
double one_minus_cosine ;
double sine ;
lib_zero_matrix( mx ) ;
COPY_COORD( axis, (*rvec) ) ;
cosine = cos( (double)angle ) ;
sine = sin( (double)angle ) ;
one_minus_cosine = 1.0 - cosine ;
mx[0][0] = SQR(axis.x) + (1.0 - SQR(axis.x)) * cosine ;
mx[0][1] = axis.x * axis.y * one_minus_cosine + axis.z * sine ;
mx[0][2] = axis.x * axis.z * one_minus_cosine - axis.y * sine ;
mx[1][0] = axis.x * axis.y * one_minus_cosine - axis.z * sine ;
mx[1][1] = SQR(axis.y) + (1.0 - SQR(axis.y)) * cosine ;
mx[1][2] = axis.y * axis.z * one_minus_cosine + axis.x * sine ;
mx[2][0] = axis.x * axis.z * one_minus_cosine + axis.y * sine ;
mx[2][1] = axis.y * axis.z * one_minus_cosine - axis.x * sine ;
mx[2][2] = SQR(axis.z) + (1.0 - SQR(axis.z)) * cosine ;
mx[3][3] = 1.0 ;
}
/*
* Multiply a 4 element vector by a matrix.
*/
lib_transform_coord( vres, vec, mx )
COORD4 *vres ;
COORD4 *vec ;
MATRIX mx ;
{
vres->x =
vec->x*mx[0][0] + vec->y*mx[1][0] + vec->z*mx[2][0] + vec->w*mx[3][0] ;
vres->y =
vec->x*mx[0][1] + vec->y*mx[1][1] + vec->z*mx[2][1] + vec->w*mx[3][1] ;
vres->z =
vec->x*mx[0][2] + vec->y*mx[1][2] + vec->z*mx[2][2] + vec->w*mx[3][2] ;
vres->w =
vec->x*mx[0][3] + vec->y*mx[1][3] + vec->z*mx[2][3] + vec->w*mx[3][3] ;
}
/*
* Multiply two 4x4 matrices.
*/
lib_matrix_multiply( mxres, mx1, mx2 )
MATRIX mxres ;
MATRIX mx1 ;
MATRIX mx2 ;
{
long i ;
long j ;
for ( i = 0; i < 4; i++ ) {
for ( j = 0; j < 4; j++ ) {
mxres[i][j] = mx1[i][0]*mx2[0][j] +
mx1[i][1]*mx2[1][j] +
mx1[i][2]*mx2[2][j] +
mx1[i][3]*mx2[3][j] ;
}
}
}
/*
* Rotate a vector pointing towards the major-axis faces (i.e. the major-axis
* component of the vector is defined as the largest value) 90 degrees to
* another cube face. Mod_face is a face number.
*
* If the routine is called six times, with mod_face=0..5, the vector will be
* rotated to each face of a cube. Rotations are:
* mod_face = 0 mod 3, +Z axis rotate
* mod_face = 1 mod 3, +X axis rotate
* mod_face = 2 mod 3, -Y axis rotate
*/
lib_rotate_cube_face( vec, major_axis, mod_face )
COORD4 *vec ;
long major_axis ;
long mod_face ;
{
double swap ;
mod_face = (mod_face+major_axis) % 3 ;
if ( mod_face == 0 ) {
swap = vec->x ;
vec->x = -vec->y ;
vec->y = swap ;
}
else if ( mod_face == 1 ) {
swap = vec->y ;
vec->y = -vec->z ;
vec->z = swap ;
}
else {
swap = vec->x ;
vec->x = -vec->z ;
vec->z = swap ;
}
}
/*
* Portable gaussian random number generator (from "Numerical Recipes", GASDEV)
* Returns a uniform random deviate between 0.0 and 1.0. 'iseed' must be
* less than M1 to avoid repetition, and less than (2**31-C1)/A1 [= 300718]
* to avoid overflow.
*/
#define M1 134456
#define IA1 8121
#define IC1 28411
#define RM1 1.0/M1
double lib_gauss_rand(iseed)
long iseed ;
{
double fac ;
long ix1, ix2 ;
double r ;
double v1, v2 ;
ix2 = iseed ;
do {
ix1 = (IC1+ix2*IA1) % M1 ;
ix2 = (IC1+ix1*IA1) % M1 ;
v1 = ix1 * 2.0 * RM1 - 1.0 ;
v2 = ix2 * 2.0 * RM1 - 1.0 ;
r = v1*v1 + v2*v2 ;
} while ( r >= 1.0 ) ;
fac = sqrt( (double)( -2.0 * log( (double)r ) / r ) ) ;
return( v1 * fac ) ;
}
/* OUTPUT ROUTINES
*
* Files are output as lines of text. For each entity, the first line
* defines its type. The rest of the first line and possibly other lines
* contain further information about the entity. Entities include:
*
* "v" - viewing vectors and angles
* "l" - positional light location
* "b" - background color
* "f" - object material properties
* "c" - cone or cylinder primitive
* "s" - sphere primitive
* "p" - polygon primitive
* "pp" - polygonal patch primitive
*/
/*
* Output viewpoint location. The parameters are:
* From: the eye location.
* At: a position to be at the center of the image. A.k.a. "lookat"
* Up: a vector defining which direction is up.
*
* Note that no assumptions are made about normalizing the data (e.g. the
* from-at distance does not have to be 1). Also, vectors are not
* required to be perpendicular to each other.
*
* For all databases some viewing parameters are always the same:
*
* Viewing angle is defined as from the center of top pixel row to bottom
* pixel row and left column to right column.
* Yon is "at infinity."
* Resolution is always 512 x 512.
*/
lib_output_viewpoint( from, at, up, angle, hither, resx, resy )
COORD4 *from ;
COORD4 *at ;
COORD4 *up ;
double angle ;
double hither ;
long resx ;
long resy ;
{
printf( "v\n" ) ;
printf( "from %g %g %g\n", from->x, from->y, from->z ) ;
printf( "at %g %g %g\n", at->x, at->y, at->z ) ;
printf( "up %g %g %g\n", up->x, up->y, up->z ) ;
printf( "angle %g\n", angle ) ;
printf( "hither %g\n", hither ) ;
printf( "resolution %d %d\n", resx, resy ) ;
}
/*
* Output light. A light is defined by position. All lights have the same
* intensity.
*
*/
lib_output_light( center_pt )
COORD4 *center_pt ;
{
printf( "l %g %g %g\n", center_pt->x, center_pt->y, center_pt->z ) ;
}
/*
* Output background color. A color is simply RGB (monitor dependent, but
* that's life). The format is:
* "b" red green blue
*/
lib_output_background_color( color )
COORD4 *color ;
{
printf( "b %g %g %g\n", color->x, color->y, color->z ) ;
}
/*
* Output a color and shading parameters for the object in the format:
* "f" red green blue Kd Ks Shine T index_of_refraction
*
* Kd is the diffuse component, Ks the specular, Shine is the Phong cosine
* power for highlights, T is transmittance (fraction of light passed per
* unit). 0 <= Kd <= 1 and 0 <= Ks <= 1, though it is not required that
* Kd + Ks == 1.
*
* The fill color is used to color the objects following it until a new color
* is assigned or the file ends.
*/
lib_output_color( color, kd, ks, shine, t, i_of_r )
COORD4 *color ;
double kd ;
double ks ;
double shine ;
double t ;
double i_of_r ;
{
printf( "f %g %g %g %g %g %g %g %g\n", color->x, color->y, color->z,
kd, ks, shine, t, i_of_r ) ;
}
/*
* Output cylinder or cone. A cylinder is defined as having a radius and an
* axis defined by two points, which also define the top and bottom edge of the
* cylinder. A cone is defined similarly, the difference being that the apex
* and base radii are different. The apex radius is defined as being smaller
* than the base radius. Note that the surface exists without endcaps.
*
* If format=OUTPUT_CURVES, output the cylinder/cone in format:
* "c"
* base.x base.y base.z base_radius
* apex.x apex.y apex.z apex_radius
*
* If the format=OUTPUT_POLYGONS, the surface is polygonalized and output.
* (4*OUTPUT_RESOLUTION) polygons are output as rectangles by
* lib_output_polypatch.
*/
lib_output_cylcone( base_pt, apex_pt, format )
COORD4 *base_pt ;
COORD4 *apex_pt ;
long format ;
{
double angle ;
COORD4 axis ;
COORD4 dir ;
double divisor ;
COORD4 lip_norm[4], lip_pt[4] ;
MATRIX mx ;
COORD4 norm_axis ;
long num_pol ;
COORD4 start_norm, start_radius[4] ;
if ( format == OUTPUT_CURVES ) {
printf( "c\n" ) ;
printf( "%g %g %g %g\n",
base_pt->x, base_pt->y, base_pt->z, base_pt->w ) ;
printf( "%g %g %g %g\n",
apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w ) ;
}
else {
SUB3_COORD( axis, (*apex_pt), (*base_pt) ) ;
COPY_COORD( norm_axis, axis ) ;
lib_normalize_coord3( &norm_axis ) ;
dir.x = 0.0 ; dir.y = 0.0 ; dir.z = 1.0 ; dir.w = 0.0 ;
CROSS( start_norm, axis, dir ) ;
divisor = lib_normalize_coord3( &start_norm ) ;
if ( ABSOLUTE( divisor ) < EPSILON ) {
dir.x = 1.0 ; dir.y = 0.0 ; dir.z = 0.0 ;
CROSS( start_norm, axis, dir ) ;
lib_normalize_coord3( &start_norm ) ;
}
start_radius[0].x = start_norm.x * base_pt->w ;
start_radius[0].y = start_norm.y * base_pt->w ;
start_radius[0].z = start_norm.z * base_pt->w ;
start_radius[0].w = 0.0 ;
ADD3_COORD( lip_pt[0], (*base_pt), start_radius[0] ) ;
start_radius[1].x = start_norm.x * apex_pt->w ;
start_radius[1].y = start_norm.y * apex_pt->w ;
start_radius[1].z = start_norm.z * apex_pt->w ;
start_radius[1].w = 0.0 ;
ADD3_COORD( lip_pt[1], (*apex_pt), start_radius[1] ) ;
COPY_COORD4( lip_norm[0], start_norm ) ;
COPY_COORD4( lip_norm[1], start_norm ) ;
for ( num_pol = 0 ; num_pol < 4*OUTPUT_RESOLUTION ; ++num_pol ) {
COPY_COORD4( lip_pt[3], lip_pt[0] ) ;
COPY_COORD4( lip_pt[2], lip_pt[1] ) ;
COPY_COORD4( lip_norm[3], lip_norm[0] ) ;
COPY_COORD4( lip_norm[2], lip_norm[1] ) ;
angle = 2.0 * PI *
(double)( num_pol+1 ) / (double)( 4*OUTPUT_RESOLUTION ) ;
lib_create_axis_rotate_matrix( mx, &norm_axis, angle ) ;
lib_transform_coord( &lip_pt[0], &start_radius[0], mx ) ;
ADD2_COORD( lip_pt[0], (*base_pt) ) ;
lib_transform_coord( &lip_pt[1], &start_radius[1], mx ) ;
ADD2_COORD( lip_pt[1], (*apex_pt) ) ;
lib_transform_coord( &lip_norm[0], &start_norm, mx ) ;
COPY_COORD4( lip_norm[1], lip_norm[0] ) ;
lib_output_polypatch( 4, lip_pt, lip_norm ) ;
}
}
}
/*
* Output sphere. A sphere is defined by a radius and center position.
*
* If format=OUTPUT_CURVES, output the sphere in format:
* "s" center.x center.y center.z radius
*
* If the format=OUTPUT_POLYGONS, the sphere is polygonalized and output.
* The sphere is polygonalized by splitting it into 6 faces (of a cube
* projected onto the sphere) and dividing these faces by equally spaced
* great circles. OUTPUT_RESOLUTION affects the number of great circles.
* (6*2*OUTPUT_RESOLUTION*OUTPUT_RESOLUTION) polygons are output as triangles
* using lib_output_polypatch.
*/
lib_output_sphere( center_pt, format )
COORD4 *center_pt ;
long format ;
{
double angle ;
COORD4 edge_norm[3], edge_pt[3] ;
long num_face, num_edge, num_tri, num_vert ;
COORD4 x_axis[OUTPUT_RESOLUTION+1], y_axis[OUTPUT_RESOLUTION+1] ;
COORD4 pt[OUTPUT_RESOLUTION+1][OUTPUT_RESOLUTION+1] ;
COORD4 mid_axis ;
MATRIX rot_mx ;
long u_pol, v_pol ;
if ( format == OUTPUT_CURVES ) {
printf( "s %g %g %g %g\n",
center_pt->x, center_pt->y, center_pt->z, center_pt->w ) ;
}
else {
/* calculate axes used to find grid points */
for ( num_edge = 0 ; num_edge <= OUTPUT_RESOLUTION ; ++num_edge ) {
angle = (PI/4.0) * (2.0*(double)num_edge/OUTPUT_RESOLUTION - 1.0) ;
mid_axis.w = 0.0 ;
mid_axis.x = 1.0 ; mid_axis.y = 0.0 ; mid_axis.z = 0.0 ;
lib_create_rotate_matrix( rot_mx, Y_AXIS, angle ) ;
lib_transform_coord( &x_axis[num_edge], &mid_axis, rot_mx ) ;
mid_axis.x = 0.0 ; mid_axis.y = 1.0 ; mid_axis.z = 0.0 ;
lib_create_rotate_matrix( rot_mx, X_AXIS, angle ) ;
lib_transform_coord( &y_axis[num_edge], &mid_axis, rot_mx ) ;
}
/* set up grid of points on +Z sphere surface */
for ( u_pol = 0 ; u_pol <= OUTPUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol <= OUTPUT_RESOLUTION ; ++v_pol ) {
CROSS( pt[u_pol][v_pol], x_axis[u_pol], y_axis[v_pol] ) ;
lib_normalize_coord3( &pt[u_pol][v_pol] ) ;
pt[u_pol][v_pol].w = 1.0 ;
}
}
for ( num_face = 0 ; num_face < 6 ; ++num_face ) {
/* transform points to cube face */
for ( u_pol = 0 ; u_pol <= OUTPUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol <= OUTPUT_RESOLUTION ; ++v_pol ) {
lib_rotate_cube_face( &pt[u_pol][v_pol]
, Z_AXIS
, num_face
) ;
}
}
/* output grid */
for ( u_pol = 0 ; u_pol < OUTPUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol < OUTPUT_RESOLUTION ; ++v_pol ) {
for ( num_tri = 0 ; num_tri < 2 ; ++num_tri ) {
for ( num_edge = 0 ; num_edge < 3 ; ++num_edge ) {
num_vert = (num_tri*2 + num_edge) % 4 ;
if ( num_vert == 0 ) {
COPY_COORD4( edge_pt[num_edge],
pt[u_pol][v_pol] ) ;
}
else if ( num_vert == 1 ) {
COPY_COORD4( edge_pt[num_edge],
pt[u_pol][v_pol+1] ) ;
}
else if ( num_vert == 2 ) {
COPY_COORD4( edge_pt[num_edge],
pt[u_pol+1][v_pol+1] ) ;
}
else {
COPY_COORD4( edge_pt[num_edge],
pt[u_pol+1][v_pol] ) ;
}
COPY_COORD4( edge_norm[num_edge],
edge_pt[num_edge] ) ;
edge_pt[num_edge].x =
edge_pt[num_edge].x * center_pt->w +
center_pt->x ;
edge_pt[num_edge].y =
edge_pt[num_edge].y * center_pt->w +
center_pt->y ;
edge_pt[num_edge].z =
edge_pt[num_edge].z * center_pt->w +
center_pt->z ;
}
lib_output_polypatch( 3, edge_pt, edge_norm ) ;
}
}
}
}
}
}
/*
* Output polygon. A polygon is defined by a set of vertices. With these
* databases, a polygon is defined to have all points coplanar. A polygon has
* only one side, with the order of the vertices being counterclockwise as you
* face the polygon (right-handed coordinate system).
*
* The output format is always:
* "p" total_vertices
* vert1.x vert1.y vert1.z
* [etc. for total_vertices polygons]
*
*/
lib_output_polygon( tot_vert, vert )
long tot_vert ;
COORD4 *vert ;
{
long num_vert ;
printf( "p %d\n", tot_vert ) ;
for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
printf( "%g %g %g\n", vert[num_vert].x
, vert[num_vert].y
, vert[num_vert].z
) ;
}
}
/*
* Output polygonal patch. A patch is defined by a set of vertices and their
* normals. With these databases, a patch is defined to have all points
* coplanar. A patch has only one side, with the order of the vertices being
* counterclockwise as you face the patch (right-handed coordinate system).
*
* The output format is always:
* "pp" total_vertices
* vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z
* [etc. for total_vertices polygonal patches]
*
*/
lib_output_polypatch( tot_vert, vert, norm )
long tot_vert ;
COORD4 *vert ;
COORD4 *norm ;
{
long num_vert ;
printf( "pp %d\n", tot_vert ) ;
for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
printf( "%g %g %g %g %g %g\n", vert[num_vert].x
, vert[num_vert].y
, vert[num_vert].z
, norm[num_vert].x
, norm[num_vert].y
, norm[num_vert].z
) ;
}
}
@EOF
chmod 644 lib.c
echo x - lib.h
cat >lib.h <<'@EOF'
/*
* lib.h - vector library definitions
*
* Version: 2.2 (11/17/87)
* Author: Eric Haines, 3D/Eye, Inc.
*/
#define X_AXIS 0
#define Y_AXIS 1
#define Z_AXIS 2
/* Output library definitions */
#define OUTPUT_CURVES 0 /* true curve output */
#define OUTPUT_PATCHES 1 /* polygonal patches output */
#define OUTPUT_RESOLUTION 4 /* amount of polygonalization */
double lib_normalize_coord3() ;
double lib_gauss_rand() ;
@EOF
chmod 640 lib.h
echo x - lookat.c
cat >lookat.c <<'@EOF'
/************************************************************************/
/* */
/* program: lookat */
/* */
/* usage: lookat [filename] */
/* */
/* function: examine a file in my neutral file format. */
/* Creates a display list, uses the mouse to move */
/* around (left/right - rotate on screen's y axis, */
/* up/down - rotate on screen's x axis, left */
/* button - move closer, right button - move back. */
/* Buttons also move the screen's axis' z-depth). */
/* */
/* input: filename.nff */
/* Define OUTDEV, OUTDRIVER, INDEV and INDRIVER */
/* (default is SRX and mouse if not defined). */
/* If redefined, make sure the makefile links in */
/* the libraries you need. gescape commands may */
/* also have to be modified or deleted. */
/* */
/* output: a display on the screen */
/* */
/* comments: program components are described within the */
/* corresponding modules */
/* */
/* author: Eric Haines, 12/5/86 */
/* */
/************************************************************************/
#include <stdio.h>
#include <math.h>
#include <fcntl.h>
#include <starbase.c.h>
#include <sbdl.c.h>
#include "def.h"
#include "lib.h"
#define NEG_COORD(r) (r).x = -(r).x, (r).y = -(r).y, (r).z = -(r).z
extern char *getenv() ;
int devopen() ;
#define BUFSIZE 255
#define OUT_RESOLUTION 4
#define MAX_EDGES 255 /* maximum edges in a polygon */
#define SEG_DATA 1
/* default devices and drivers */
char default_indev[] = "/dev/hil2" ;
char default_indriver[] = "hp-hil" ;
char default_outdev[] = "/dev/crt" ;
char default_outdriver[] = "hp98721" ;
static camera_arg camera ;
COORD4 from ;
COORD4 at ;
COORD4 up ;
static int screendes ;
static int inputdes ;
main(argc,argv)
int argc; char *argv[];
{
char *device, *driver ;
int create_database() ;
from.x = from.y = from.z = 0.0 ;
at.x = 0.0 ; at.y = 1.0 ; at.z = 0.0 ;
up.x = 0.0 ; up.y = 0.0 ; up.z = 1.0 ;
screendes = devopen(OUTDEV,INIT|THREE_D|MODEL_XFORM) ;
if ( screendes == -1 ) {
printf("error opening output device\n" ) ;
exit(1) ;
}
inputdes = devopen(INDEV,INIT) ;
if ( inputdes == -1 ) {
printf("error opening input device\n" ) ;
exit(1) ;
}
vdc_extent(inputdes,-1.0,-0.8,0.8, 1.0,0.8,0.8 ) ;
crt_setup() ;
camera_setup() ;
if ( !create_database( argc, argv ) ) {
exit(1) ;
}
showtime() ;
disable_events( inputdes );
gclose( inputdes ) ;
gclose( screendes ) ;
}
crt_setup()
/* this may have to be modified if the various gescapes are
* not supported on your device */
{
gescape_arg arg1,arg2 ;
buffer_mode ( screendes
, TRUE ) ; /* buffering is on */
gescape( screendes, SWITCH_SEMAPHORE, &arg1, &arg1 ) ;
arg1.f[0] = 1.0 ;
gescape( screendes, LS_OVERFLOW_CONTROL, &arg1, &arg2 ) ;
shade_mode ( screendes
, INIT | CMAP_FULL /* full color map */
, TRUE ) ; /* use light source
equations */
double_buffer ( screendes
, TRUE | INIT /* Enable double buffer and
initialize color map
accordingly. */
, 12 ) ; /* 12 planes for each buffer */
clear_control(screendes,CLEAR_DISPLAY_SURFACE|CLEAR_ALL_BANKS) ;
clear_view_surface(screendes) ;
clear_control(screendes,CLEAR_VIEWPORT) ;
}
camera_setup()
{
camera.front = 0.0 ;
camera.back = 100.0 ;
camera.projection = CAM_PERSPECTIVE ;
}
showtime()
{
int curr_buffer ;
float dummy ;
int frame ;
int ok ;
int mbutton ;
float x_change, y_change ;
hidden_surface ( screendes
, TRUE /* enable hidden surface
removal */
, TRUE
) ; /* cull back-facing
polygons */
set_locator(inputdes,1,0.0, 0.0, 0.0 ) ;
clear_view_surface(screendes);
for ( frame = 0, curr_buffer=0; frame < 10000; ++frame ) {
sample_locator( inputdes,1,&ok,&x_change,&y_change,&dummy);
sample_choice(inputdes,1,&ok,&mbutton);
set_locator(inputdes,1,0.0, 0.0, 0.0 ) ;
move_camera(x_change,y_change,mbutton) ;
zbuffer_switch(screendes,1) ; /* clear z-buffer */
draw_object() ;
/* Switch buffers */
curr_buffer = !curr_buffer ;
dbuffer_switch( screendes, curr_buffer ) ;
make_picture_current( screendes ) ;
}
}
move_camera( x_change, y_change, mbutton )
float x_change ;
float y_change ;
int mbutton ;
{
COORD4 toat, out, toward, axis, new_toat, new_up, moveat ;
double angle, dot_prod, toat_distance ;
int i, j ;
MATRIX mx ;
static double mmove = 0.1 ;
float viewmx[4][4] ;
/* find CROSS product of to-at & up */
SUB3_COORD( toat, at, from ) ;
CROSS( out, toat, up ) ;
/* perpendicularize and normalize up wrto toat */
toat_distance = lib_normalize_coord3( &toat ) ;
lib_normalize_coord3( &out ) ;
lib_normalize_coord3( &toat ) ;
CROSS( up, out, toat ) ;
/* find new toat to move to */
toward.x = x_change * out.x - y_change * up.x + toat.x ;
toward.y = x_change * out.y - y_change * up.y + toat.y ;
toward.z = x_change * out.z - y_change * up.z + toat.z ;
/* find angle between toat and new toat */
lib_normalize_coord3( &toward ) ;
dot_prod = DOT_PRODUCT( toat, toward ) ;
if ( ABSOLUTE(dot_prod) <= 1.000 ) {
angle = acos( dot_prod ) ;
CROSS( axis, toat, toward ) ;
/* angle to rotate */
lib_normalize_coord3( &axis ) ;
lib_create_axis_rotate_matrix( mx, &axis, angle ) ;
toat.w = 0.0 ;
lib_transform_coord( &new_toat, &toat, mx ) ;
from.x = at.x - new_toat.x * toat_distance ;
from.y = at.y - new_toat.y * toat_distance ;
from.z = at.z - new_toat.z * toat_distance ;
up.w = 0.0 ;
lib_transform_coord( &new_up, &up, mx ) ;
COPY_COORD( up, new_up ) ;
}
SUB3_COORD( toat, at, from ) ;
lib_normalize_coord3( &toat ) ;
if ( mbutton != 0 ) {
moveat.x = toat.x * mmove ;
moveat.y = toat.y * mmove ;
moveat.z = toat.z * mmove ;
mmove = mmove * 1.7 ;
if ( mmove > 1.0 ) {
mmove = 1.0 ;
}
if ( mbutton == 2 ) {
NEG_COORD( moveat ) ;
}
ADD2_COORD( from, moveat ) ;
ADD2_COORD( at, moveat ) ;
}
else {
mmove = 0.1 ;
}
camera.camx = from.x ;
camera.camy = from.y ;
camera.camz = from.z ;
camera.upx = up.x ;
camera.upy = up.y ;
camera.upz = up.z ;
camera.refx = camera.camx + toat.x ;
camera.refy = camera.camy + toat.y ;
camera.refz = camera.camz + toat.z ;
/* view right handed coords */
/*
for ( i = 0 ; i < 4 ; ++i ) {
for ( j = 0 ; j < 4 ; ++j ) {
if ( i == j ) {
viewmx[i][j] = 1.0 ;
}
else {
viewmx[i][j] = 0.0 ;
}
}
}
viewmx[0][0] = -1.0 ;
view_matrix3d( screendes, viewmx, POST_CONCAT_VW ) ;
*/
view_camera( screendes, &camera ) ;
}
draw_object()
{
refresh_segment(screendes,SEG_DATA) ;
}
int create_database(argc,argv)
int argc; char *argv[];
{
gescape_arg arg1, arg2 ;
COORD4 apex ;
COORD4 base ;
char buffer[BUFSIZE] ;
COORD4 center ;
FILE *fd ;
double hither ;
int int_shine ;
double kd, ks, shine, t, i_of_r ;
int light_flag ;
double light_int ;
double light_color[3] ;
double light_pt[24] ;
int num_arg ;
int num_light ;
int num_vert ;
double poly_color[3] ;
int polygon_format ; /* 0 - 3pt, 1 - 6pt w/normal */
int spec_flag ;
int tot_light ;
int tot_vert ;
float vert[MAX_EDGES*6] ;
int xresolution ;
int yresolution ;
polygon_format = -1 ;
tot_light = 0 ;
open_segment(screendes,SEG_DATA,TRUE,TRUE);
num_arg = 1 ;
do {
if ( num_arg >= argc ) {
fd = stdin ;
}
else {
if ( ( fd = fopen( argv[num_arg], "r" ) ) == NULL ) {
fprintf( stderr, "cannot open file %s. Bye!\n", argv[num_arg] ) ;
return( FALSE ) ;
}
}
while ( fgets( buffer, BUFSIZE, fd ) ) {
/* polygonal patch */
if ( sscanf( buffer, "pp %d", &tot_vert ) == 1 ) {
for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%f %f %f %f %f %f",
&vert[num_vert*6],
&vert[num_vert*6+1],
&vert[num_vert*6+2],
&vert[num_vert*6+3],
&vert[num_vert*6+4],
&vert[num_vert*6+5] ) ;
}
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
polygon3d(screendes, vert, tot_vert, FALSE ) ;
}
/* polygon */
else if ( sscanf( buffer, "p %d", &tot_vert ) == 1 ) {
for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%f %f %f", &vert[num_vert*3],
&vert[num_vert*3+1],
&vert[num_vert*3+2] ) ;
}
if ( polygon_format != 0 ) {
polygon_format = 0 ;
vertex_format ( screendes
, 0 /* # no extra coordinates */
, 0 /* # coordinates used for
normal determination */
, FALSE /* no extra coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
polygon3d(screendes, vert, tot_vert, FALSE ) ;
}
/* sphere */
else if ( sscanf( buffer, "s %lf %lf %lf %lf",
¢er.x, ¢er.y, ¢er.z, ¢er.w ) == 4 ) {
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
sphere( screendes, ¢er ) ;
}
/* cylinder / cone */
else if ( buffer[0] == 'c' ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%lf %lf %lf %lf", &base.x, &base.y, &base.z, &base.w ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%lf %lf %lf %lf", &apex.x, &apex.y, &apex.z, &apex.w ) ;
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
cylcone( screendes, &base, &apex ) ;
}
/* fill color */
else if ( sscanf( buffer, "f %lf %lf %lf %lf %lf %lf %lf"
, &poly_color[0]
, &poly_color[1]
, &poly_color[2]
, &kd
, &ks
, &shine
, &t
, &i_of_r
) == 7 ) {
if ( t > 0.0 ) {
arg1.i[0] = 0x5A5A ;
kd = 1.0 ;
}
else {
arg1.i[0] = 0xFFFF ;
}
gescape(screendes, TRANSPARENCY, &arg1, &arg2 ) ;
fill_color(screendes, (float)(poly_color[0]*kd)
, (float)(poly_color[1]*kd)
, (float)(poly_color[2]*kd)
) ;
spec_flag = ( ks > 0.0 ) ;
int_shine = (int)(shine+0.5) ;
surface_model(screendes, spec_flag
, int_shine >= 1 ? int_shine : 1
, (float)(poly_color[0]*ks)
, (float)(poly_color[1]*ks)
, (float)(poly_color[2]*ks)
) ;
}
/* light */
else if ( sscanf( buffer, "l %lf %lf %lf", &light_pt[tot_light*3+0],
&light_pt[tot_light*3+1],
&light_pt[tot_light*3+2]
) == 3 ) {
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
arg1.i[0] = 0x5A5A ;
gescape(screendes, TRANSPARENCY, &arg1, &arg2 ) ;
light_color[0] = 1.0 ;
light_color[1] = 1.0 ;
light_color[2] = 1.0 ;
fill_color(screendes, (float)light_color[0]
, (float)light_color[1]
, (float)light_color[2]
) ;
surface_model(screendes, 1, 1, 0.0,0.0,0.0 ) ;
center.x = light_pt[tot_light*3+0] ;
center.y = light_pt[tot_light*3+1] ;
center.z = light_pt[tot_light*3+2] ;
center.w = 0.1 ;
sphere( screendes, ¢er ) ;
++tot_light ;
}
/* view */
else if ( buffer[0] == 'v' ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "from %lf %lf %lf", &from.x, &from.y, &from.z ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "at %lf %lf %lf", &at.x, &at.y, &at.z ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "up %lf %lf %lf", &up.x, &up.y, &up.z ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "angle %f", &camera.field_of_view ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "hither %lf", &hither ) ;
camera.front = (float)(hither - 1.0) ;
fgets( buffer, BUFSIZE, fd ) ;
/* ???? unused for now */
sscanf( buffer, "resolution %d %d\n", &xresolution, &yresolution ) ;
}
/* background color */
else if ( sscanf( buffer, "b %lf %lf %lf", &poly_color[0],
&poly_color[1],
&poly_color[2]
) == 3 ) {
background_color(screendes,
(float)poly_color[0],(float)poly_color[1],(float)poly_color[2]) ;
clear_view_surface(screendes) ;
}
/* error */
else {
fprintf( stderr, "Error analyzing %s\n", buffer ) ;
}
}
if ( num_arg < argc ) {
fclose( fd ) ;
}
} while ( ++num_arg < argc ) ;
close_segment(screendes) ;
/* set up lights */
light_flag = 2 ;
if ( tot_light == 0 ) {
light_ambient(screendes,1.0,1.0,1.0);
}
else {
light_int = sqrt((double)tot_light) / (double)(tot_light*2) ;
light_ambient(screendes,(float)light_int,(float)light_int,(float)light_int ) ;
for ( num_light = 0 ; num_light < tot_light ; ++num_light ) {
light_flag *= 2 ;
light_source(screendes,num_light+1,POSITIONAL,
(float)light_int,(float)light_int,(float)light_int,
(float)light_pt[num_light*3],
(float)light_pt[num_light*3+1],
(float)light_pt[num_light*3+2] ) ;
light_model(screendes,num_light+1,
0,1,10.0,30.0,1.0,1.0,1.0) ;
}
}
light_switch(screendes,light_flag-1);
return( TRUE ) ;
}
/*
* Output cylinder or cone. A cylinder is defined as having a radius and an axis
* defined by two points, which also define the top and bottom edge of the
* cylinder. A cone is defined similarly, the difference being that the apex
* and base radii are different. The apex radius is defined as being smaller
* than the base radius. Note that the surface exists without endcaps.
*/
cylcone( fildes, base_pt, apex_pt )
int fildes ;
COORD4 *base_pt ;
COORD4 *apex_pt ;
{
double angle ;
COORD4 axis ;
COORD4 dir ;
double divisor ;
int i ;
COORD4 lip_coord, lip_cnorm ;
float lip_pt[24] ;
MATRIX mx ;
COORD4 norm_axis ;
int num_pol ;
COORD4 start_norm, start_radius[4] ;
SUB3_COORD( axis, (*apex_pt), (*base_pt) ) ;
COPY_COORD( norm_axis, axis ) ;
lib_normalize_coord3( &norm_axis ) ;
dir.x = 0.0 ; dir.y = 0.0 ; dir.z = 1.0 ; dir.w = 0.0 ;
CROSS( start_norm, axis, dir ) ;
divisor = lib_normalize_coord3( &start_norm ) ;
if ( ABSOLUTE( divisor ) < EPSILON ) {
dir.x = 1.0 ; dir.y = 0.0 ; dir.z = 0.0 ;
CROSS( start_norm, axis, dir ) ;
lib_normalize_coord3( &start_norm ) ;
}
start_radius[0].x = start_norm.x * base_pt->w ;
start_radius[0].y = start_norm.y * base_pt->w ;
start_radius[0].z = start_norm.z * base_pt->w ;
start_radius[0].w = 0.0 ;
lip_pt[0] = base_pt->x + start_radius[0].x ;
lip_pt[1] = base_pt->y + start_radius[0].y ;
lip_pt[2] = base_pt->z + start_radius[0].z ;
start_radius[1].x = start_norm.x * apex_pt->w ;
start_radius[1].y = start_norm.y * apex_pt->w ;
start_radius[1].z = start_norm.z * apex_pt->w ;
start_radius[1].w = 0.0 ;
lip_pt[6] = apex_pt->x + start_radius[1].x ;
lip_pt[7] = apex_pt->y + start_radius[1].y ;
lip_pt[8] = apex_pt->z + start_radius[1].z ;
lip_pt[3] = lip_pt[9] = start_norm.x ;
lip_pt[4] = lip_pt[10] = start_norm.y ;
lip_pt[5] = lip_pt[11] = start_norm.z ;
for ( num_pol = 0 ; num_pol < 4*OUT_RESOLUTION ; ++num_pol ) {
for ( i = 0 ; i < 6 ; ++i ) {
lip_pt[i+18] = lip_pt[i] ;
lip_pt[i+12] = lip_pt[i+6] ;
}
angle = 2.0 * PI *
(double)( num_pol+1 ) / (double)( 4*OUT_RESOLUTION ) ;
lib_create_axis_rotate_matrix( mx, &norm_axis, angle ) ;
lib_transform_coord( &lip_coord, &start_radius[0], mx ) ;
ADD2_COORD( lip_coord, (*base_pt) ) ;
lip_pt[0] = lip_coord.x ;
lip_pt[1] = lip_coord.y ;
lip_pt[2] = lip_coord.z ;
lib_transform_coord( &lip_coord, &start_radius[1], mx ) ;
ADD2_COORD( lip_coord, (*apex_pt) ) ;
lip_pt[6] = lip_coord.x ;
lip_pt[7] = lip_coord.y ;
lip_pt[8] = lip_coord.z ;
lib_transform_coord( &lip_cnorm, &start_norm, mx ) ;
lip_pt[3] = lip_pt[9] = lip_cnorm.x ;
lip_pt[4] = lip_pt[10] = lip_cnorm.y ;
lip_pt[5] = lip_pt[11] = lip_cnorm.z ;
polygon3d( fildes, lip_pt, 4, FALSE ) ;
}
}
/*
* Output sphere. A sphere is defined by a radius and center position.
*/
sphere( fildes, center_pt )
int fildes ;
COORD4 *center_pt ;
{
double angle ;
float edge_pt[18] ;
int num_face, num_edge, num_tri, num_vert ;
COORD4 x_axis[OUT_RESOLUTION+1], y_axis[OUT_RESOLUTION+1] ;
COORD4 pt[OUT_RESOLUTION+1][OUT_RESOLUTION+1] ;
COORD4 mid_axis ;
MATRIX rot_mx ;
int u_pol, v_pol ;
int u_vert, v_vert ;
/* calculate axes used to find grid points */
for ( num_edge = 0 ; num_edge <= OUT_RESOLUTION ; ++num_edge ) {
angle = (PI/4.0) * ( 2.0*(double)num_edge/OUT_RESOLUTION - 1.0 ) ;
mid_axis.w = 0.0 ;
mid_axis.x = 1.0 ; mid_axis.y = 0.0 ; mid_axis.z = 0.0 ;
lib_create_rotate_matrix( rot_mx, Y_AXIS, angle ) ;
lib_transform_coord( &x_axis[num_edge], &mid_axis, rot_mx ) ;
mid_axis.x = 0.0 ; mid_axis.y = 1.0 ; mid_axis.z = 0.0 ;
lib_create_rotate_matrix( rot_mx, X_AXIS, angle ) ;
lib_transform_coord( &y_axis[num_edge], &mid_axis, rot_mx ) ;
}
/* set up grid of points on +Z sphere surface */
for ( u_pol = 0 ; u_pol <= OUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol <= OUT_RESOLUTION ; ++v_pol ) {
CROSS( pt[u_pol][v_pol], x_axis[u_pol], y_axis[v_pol] ) ;
lib_normalize_coord3( &pt[u_pol][v_pol] ) ;
pt[u_pol][v_pol].w = 1.0 ;
}
}
for ( num_face = 0 ; num_face < 6 ; ++num_face ) {
/* transform points to cube face */
for ( u_pol = 0 ; u_pol <= OUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol <= OUT_RESOLUTION ; ++v_pol ) {
lib_rotate_cube_face( &pt[u_pol][v_pol]
, Z_AXIS
, num_face
) ;
}
}
/* output grid */
for ( u_pol = 0 ; u_pol < OUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol < OUT_RESOLUTION ; ++v_pol ) {
for ( num_tri = 0 ; num_tri < 2 ; ++num_tri ) {
for ( num_edge = 0 ; num_edge < 3 ; ++num_edge ) {
num_vert = (num_tri*2 + num_edge) % 4 ;
if ( num_vert == 0 ) {
u_vert = u_pol ;
v_vert = v_pol ;
}
else if ( num_vert == 1 ) {
u_vert = u_pol ;
v_vert = v_pol + 1 ;
}
else if ( num_vert == 2 ) {
u_vert = u_pol + 1 ;
v_vert = v_pol + 1 ;
}
else {
u_vert = u_pol + 1 ;
v_vert = v_pol ;
}
edge_pt[num_edge*6+3] = pt[u_vert][v_vert].x ;
edge_pt[num_edge*6+4] = pt[u_vert][v_vert].y ;
edge_pt[num_edge*6+5] = pt[u_vert][v_vert].z ;
edge_pt[num_edge*6+0] =
edge_pt[num_edge*6+3] * center_pt->w +
center_pt->x ;
edge_pt[num_edge*6+1] =
edge_pt[num_edge*6+4] * center_pt->w +
center_pt->y ;
edge_pt[num_edge*6+2] =
edge_pt[num_edge*6+5] * center_pt->w +
center_pt->z ;
}
polygon3d( fildes, edge_pt, 3, FALSE ) ;
}
}
}
}
}
int devopen(dev_kind,init_mode)
int dev_kind,init_mode;
{
char *dev, *driver;
int fildes ;
if ( dev_kind == OUTDEV ) {
dev = getenv("OUTDEV");
if (!dev) dev = default_outdev ;
driver = getenv("OUTDRIVER");
if (!driver) driver = default_outdriver ;
} else {
dev = getenv("INDEV");
if (!dev) dev = default_indev ;
driver = getenv("INDRIVER");
if (!driver) driver = default_indriver ;
}
fildes = gopen(dev,dev_kind,driver,init_mode);
return(fildes) ;
}
@EOF
chmod 644 lookat.c
echo x - lookonce.c
cat >lookonce.c <<'@EOF'
/************************************************************************/
/* */
/* program: lookonce */
/* */
/* usage: lookonce [filename] */
/* */
/* function: examine a file in my neutral file format. Does */
/* not use display lists: displays as data is read.*/
/* */
/* input: filename.nff */
/* Define OUTDEV and OUTDRIVER */
/* (default is SRX if not defined) */
/* If redefined, make sure the makefile links in */
/* the libraries you need. gescape commands may */
/* also have to be modified or deleted. */
/* */
/* output: a display on the screen */
/* */
/* comments: program components are described within the */
/* corresponding modules */
/* */
/* author: Eric Haines, 3D/Eye Inc, 12/5/86 */
/* */
/************************************************************************/
#include <stdio.h>
#include <math.h>
#include <fcntl.h>
#include <starbase.c.h>
#include "def.h"
#include "lib.h"
extern char *getenv() ;
int devopen() ;
#define BUFSIZE 255
#define OUT_RESOLUTION 4
#define MAX_EDGES 255 /* maximum edges in a polygon */
/* default devices and drivers */
char default_indev[] = "/dev/hil2" ;
char default_indriver[] = "hp-hil" ;
char default_outdev[] = "/dev/crt" ;
char default_outdriver[] = "hp98721" ;
static camera_arg camera ;
COORD4 from ;
COORD4 at ;
COORD4 up ;
static int screendes ;
main(argc,argv)
int argc; char *argv[];
{
char *device, *driver ;
int create_database() ;
from.x = from.y = from.z = 0.0 ;
at.x = 0.0 ; at.y = 1.0 ; at.z = 0.0 ;
up.x = 0.0 ; up.y = 0.0 ; up.z = 1.0 ;
screendes = devopen(OUTDEV,INIT|THREE_D|MODEL_XFORM) ;
if ( screendes == -1 ) {
printf("error opening output device\n" ) ;
exit(1) ;
}
crt_setup() ;
camera_setup() ;
if ( !create_database( argc, argv ) ) {
exit(1) ;
}
gclose( screendes ) ;
}
crt_setup()
/* this may have to be modified if the various gescapes are
* not supported on your device */
{
gescape_arg arg1, arg2 ;
gescape( screendes, SWITCH_SEMAPHORE, &arg1, &arg2 ) ;
arg1.f[0] = 1.0 ;
gescape( screendes, LS_OVERFLOW_CONTROL, &arg1, &arg2 ) ;
shade_mode ( screendes
, INIT | CMAP_FULL /* full color map */
, TRUE ) ; /* use light source
equations */
clear_control(screendes,CLEAR_DISPLAY_SURFACE|CLEAR_ALL_BANKS) ;
clear_view_surface(screendes) ;
clear_control(screendes,CLEAR_VIEWPORT) ;
}
camera_setup()
{
camera.front = 0.0 ;
camera.back = 100.0 ;
camera.projection = CAM_PERSPECTIVE ;
}
int create_database(argc,argv)
int argc; char *argv[];
{
gescape_arg arg1, arg2 ;
COORD4 apex ;
COORD4 base ;
char buffer[BUFSIZE] ;
COORD4 center ;
FILE *fd ;
float hither ;
int i, j ;
int int_shine ;
float kd, ks, shine, t, i_of_r ;
int light_flag ;
float light_int ;
float light_color[3] ;
float light_pt[24] ;
int num_arg ;
int num_light ;
int num_vert ;
float poly_color[3] ;
int polygon_format ; /* 0 - 3pt, 1 - 6pt w/normal */
int spec_flag ;
COORD4 toat, out ;
int tot_light ;
int tot_vert ;
float vert[MAX_EDGES*6] ;
float viewmx[4][4] ;
int xresolution ;
int yresolution ;
polygon_format = -1 ;
tot_light = 0 ;
num_arg = 1 ;
hidden_surface ( screendes
, TRUE /* enable hidden surface
removal */
, TRUE
) ; /* cull back-facing
polygons */
zbuffer_switch(screendes,1) ; /* clear z-buffer */
do {
if ( num_arg >= argc ) {
fd = stdin ;
}
else {
if ( ( fd = fopen( argv[num_arg], "r" ) ) == NULL ) {
fprintf( stderr, "cannot open file %s. Bye!\n", argv[num_arg] ) ;
return( FALSE ) ;
}
}
while ( fgets( buffer, BUFSIZE, fd ) ) {
/* polygonal patch */
if ( sscanf( buffer, "pp %d", &tot_vert ) == 1 ) {
for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%f %f %f %f %f %f",
&vert[num_vert*6],
&vert[num_vert*6+1],
&vert[num_vert*6+2],
&vert[num_vert*6+3],
&vert[num_vert*6+4],
&vert[num_vert*6+5] ) ;
}
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
polygon3d(screendes, vert, tot_vert, FALSE ) ;
}
/* polygon */
else if ( sscanf( buffer, "p %d", &tot_vert ) == 1 ) {
for ( num_vert = 0 ; num_vert < tot_vert ; ++num_vert ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%f %f %f", &vert[num_vert*3],
&vert[num_vert*3+1],
&vert[num_vert*3+2] ) ;
}
if ( polygon_format != 0 ) {
polygon_format = 0 ;
vertex_format ( screendes
, 0 /* # no extra coordinates */
, 0 /* # coordinates used for
normal determination */
, FALSE /* no extra coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
polygon3d(screendes, vert, tot_vert, FALSE ) ;
}
/* sphere */
else if ( sscanf( buffer, "s %lf %lf %lf %lf",
¢er.x, ¢er.y, ¢er.z, ¢er.w ) == 4 ) {
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
sphere( screendes, ¢er ) ;
}
/* cylinder / cone */
else if ( buffer[0] == 'c' ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%lf %lf %lf %lf", &base.x, &base.y, &base.z, &base.w ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "%lf %lf %lf %lf", &apex.x, &apex.y, &apex.z, &apex.w ) ;
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
cylcone( screendes, &base, &apex ) ;
}
/* fill color */
else if ( sscanf( buffer, "f %f %f %f %f %f %f %f"
, &poly_color[0]
, &poly_color[1]
, &poly_color[2]
, &kd
, &ks
, &shine
, &t
, &i_of_r
) == 7 ) {
if ( t > 0.0 ) {
arg1.i[0] = 0x5A5A ;
kd = 1.0 ;
}
else {
arg1.i[0] = 0xFFFF ;
}
gescape(screendes, TRANSPARENCY, &arg1, &arg2 ) ;
fill_color(screendes, poly_color[0]*kd
, poly_color[1]*kd
, poly_color[2]*kd
) ;
spec_flag = ( ks > 0.0 ) ;
int_shine = (int)(shine+0.5) ;
surface_model(screendes, spec_flag
, int_shine >= 1 ? int_shine : 1
, poly_color[0]*ks
, poly_color[1]*ks
, poly_color[2]*ks
) ;
}
/* light */
else if ( sscanf( buffer, "l %f %f %f", &light_pt[tot_light*3+0],
&light_pt[tot_light*3+1],
&light_pt[tot_light*3+2]
) == 3 ) {
if ( polygon_format != 1 ) {
polygon_format = 1 ;
vertex_format ( screendes
, 3 /* 3 extra coordinates */
, 3 /* coordinates used for
normal determination */
, FALSE /* no color coordinates */
, FALSE /* 1st vertex is not polygon
normal */
, CLOCKWISE ) ; /* polygon vertices are in
clockwise order */
}
arg1.i[0] = 0x5A5A ;
gescape(screendes, TRANSPARENCY, &arg1, &arg2 ) ;
light_color[0] = 1.0 ;
light_color[1] = 1.0 ;
light_color[2] = 1.0 ;
fill_color(screendes, light_color[0]
, light_color[1]
, light_color[2]
) ;
surface_model(screendes, 1, 1, 0.0,0.0,0.0 ) ;
center.x = light_pt[tot_light*3+0] ;
center.y = light_pt[tot_light*3+1] ;
center.z = light_pt[tot_light*3+2] ;
center.w = 0.1 ;
sphere( screendes, ¢er ) ;
++tot_light ;
/* set up lights */
light_flag = 2 ;
if ( tot_light == 0 ) {
light_ambient(screendes,1.0,1.0,1.0);
}
else {
light_int = sqrt((float)tot_light) / (float)(tot_light*2) ;
light_ambient(screendes,light_int,light_int,light_int ) ;
for ( num_light = 0 ; num_light < tot_light ; ++num_light ) {
light_flag *= 2 ;
light_source(screendes,num_light+1,POSITIONAL,
light_int,light_int,light_int,
light_pt[num_light*3],
light_pt[num_light*3+1],
light_pt[num_light*3+2] ) ;
/*
light_model(screendes,num_light+1,
ATTEN_LIGHT,1,4.0,30.0,1.0,1.0,1.0) ;
*/
light_model(screendes,num_light+1,
0,1,400.0,30.0,1.0,1.0,1.0) ;
}
}
light_switch(screendes,light_flag-1);
}
/* view */
else if ( buffer[0] == 'v' ) {
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "from %lf %lf %lf", &from.x, &from.y, &from.z ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "at %lf %lf %lf", &at.x, &at.y, &at.z ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "up %lf %lf %lf", &up.x, &up.y, &up.z ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "angle %f", &camera.field_of_view ) ;
fgets( buffer, BUFSIZE, fd ) ;
sscanf( buffer, "hither %f", &hither ) ;
camera.front = hither - 1.0 ;
fgets( buffer, BUFSIZE, fd ) ;
/* ???? unused for now */
sscanf( buffer, "resolution %d %d\n", &xresolution, &yresolution ) ;
SUB3_COORD( toat, at, from ) ;
lib_normalize_coord3( &toat ) ;
/* find cross product of to-at & up */
CROSS( out, toat, up ) ;
/* perpendicularize and normalize up wrto toat */
CROSS( up, out, toat ) ;
lib_normalize_coord3( &up ) ;
camera.camx = from.x ;
camera.camy = from.y ;
camera.camz = from.z ;
camera.upx = up.x ;
camera.upy = up.y ;
camera.upz = up.z ;
camera.refx = camera.camx + toat.x ;
camera.refy = camera.camy + toat.y ;
camera.refz = camera.camz + toat.z ;
camera.front = hither - 1.0 ;
view_camera( screendes, &camera ) ;
/* view right handed coords - doesn't work
for ( i = 0 ; i < 4 ; ++i ) {
for ( j = 0 ; j < 4 ; ++j ) {
if ( i == j ) {
viewmx[i][j] = 1.0 ;
}
else {
viewmx[i][j] = 0.0 ;
}
}
}
viewmx[0][0] = -1.0 ;
view_matrix3d( screendes, viewmx, POST_CONCAT_VW ) ;
*/
}
/* background color */
else if ( sscanf( buffer, "b %f %f %f", &poly_color[0],
&poly_color[1],
&poly_color[2]
) == 3 ) {
background_color(screendes,
poly_color[0],poly_color[1],poly_color[2]) ;
clear_view_surface(screendes) ;
}
/* error */
else {
fprintf( stderr, "Error analyzing %s\n", buffer ) ;
}
}
if ( num_arg < argc ) {
fclose( fd ) ;
}
} while ( ++num_arg < argc ) ;
make_picture_current( screendes ) ;
return( TRUE ) ;
}
/*
* Output cylinder or cone. A cylinder is defined as having a radius and an axis
* defined by two points, which also define the top and bottom edge of the
* cylinder. A cone is defined similarly, the difference being that the apex
* and base radii are different. The apex radius is defined as being smaller
* than the base radius. Note that the surface exists without endcaps.
*/
cylcone( fildes, base_pt, apex_pt )
int fildes ;
COORD4 *base_pt ;
COORD4 *apex_pt ;
{
double angle ;
COORD4 axis ;
COORD4 dir ;
float divisor ;
int i ;
COORD4 lip_coord, lip_cnorm ;
float lip_pt[24] ;
MATRIX mx ;
COORD4 norm_axis ;
int num_pol ;
COORD4 start_norm, start_radius[4] ;
SUB3_COORD( axis, (*apex_pt), (*base_pt) ) ;
COPY_COORD( norm_axis, axis ) ;
lib_normalize_coord3( &norm_axis ) ;
dir.x = 0.0 ; dir.y = 0.0 ; dir.z = 1.0 ; dir.w = 0.0 ;
CROSS( start_norm, axis, dir ) ;
divisor = lib_normalize_coord3( &start_norm ) ;
if ( ABSOLUTE( divisor ) < EPSILON ) {
dir.x = 1.0 ; dir.y = 0.0 ; dir.z = 0.0 ;
CROSS( start_norm, axis, dir ) ;
lib_normalize_coord3( &start_norm ) ;
}
start_radius[0].x = start_norm.x * base_pt->w ;
start_radius[0].y = start_norm.y * base_pt->w ;
start_radius[0].z = start_norm.z * base_pt->w ;
start_radius[0].w = 0.0 ;
lip_pt[0] = base_pt->x + start_radius[0].x ;
lip_pt[1] = base_pt->y + start_radius[0].y ;
lip_pt[2] = base_pt->z + start_radius[0].z ;
start_radius[1].x = start_norm.x * apex_pt->w ;
start_radius[1].y = start_norm.y * apex_pt->w ;
start_radius[1].z = start_norm.z * apex_pt->w ;
start_radius[1].w = 0.0 ;
lip_pt[6] = apex_pt->x + start_radius[1].x ;
lip_pt[7] = apex_pt->y + start_radius[1].y ;
lip_pt[8] = apex_pt->z + start_radius[1].z ;
lip_pt[3] = lip_pt[9] = start_norm.x ;
lip_pt[4] = lip_pt[10] = start_norm.y ;
lip_pt[5] = lip_pt[11] = start_norm.z ;
for ( num_pol = 0 ; num_pol < 4*OUT_RESOLUTION ; ++num_pol ) {
for ( i = 0 ; i < 6 ; ++i ) {
lip_pt[i+18] = lip_pt[i] ;
lip_pt[i+12] = lip_pt[i+6] ;
}
angle = 2.0 * PI *
(float)( num_pol+1 ) / (float)( 4*OUT_RESOLUTION ) ;
lib_create_axis_rotate_matrix( mx, &norm_axis, angle ) ;
lib_transform_coord( &lip_coord, &start_radius[0], mx ) ;
ADD2_COORD( lip_coord, (*base_pt) ) ;
lip_pt[0] = lip_coord.x ;
lip_pt[1] = lip_coord.y ;
lip_pt[2] = lip_coord.z ;
lib_transform_coord( &lip_coord, &start_radius[1], mx ) ;
ADD2_COORD( lip_coord, (*apex_pt) ) ;
lip_pt[6] = lip_coord.x ;
lip_pt[7] = lip_coord.y ;
lip_pt[8] = lip_coord.z ;
lib_transform_coord( &lip_cnorm, &start_norm, mx ) ;
lip_pt[3] = lip_pt[9] = lip_cnorm.x ;
lip_pt[4] = lip_pt[10] = lip_cnorm.y ;
lip_pt[5] = lip_pt[11] = lip_cnorm.z ;
polygon3d( fildes, lip_pt, 4, FALSE ) ;
}
}
/*
* Output sphere. A sphere is defined by a radius and center position.
*/
sphere( fildes, center_pt )
int fildes ;
COORD4 *center_pt ;
{
double angle ;
float edge_pt[18] ;
int num_face, num_edge, num_tri, num_vert ;
COORD4 x_axis[OUT_RESOLUTION+1], y_axis[OUT_RESOLUTION+1] ;
COORD4 pt[OUT_RESOLUTION+1][OUT_RESOLUTION+1] ;
COORD4 mid_axis ;
MATRIX rot_mx ;
int u_pol, v_pol ;
int u_vert, v_vert ;
/* calculate axes used to find grid points */
for ( num_edge = 0 ; num_edge <= OUT_RESOLUTION ; ++num_edge ) {
angle = (PI/4.0) * ( 2.0*(float)num_edge/OUT_RESOLUTION - 1.0 ) ;
mid_axis.w = 0.0 ;
mid_axis.x = 1.0 ; mid_axis.y = 0.0 ; mid_axis.z = 0.0 ;
lib_create_rotate_matrix( rot_mx, Y_AXIS, angle ) ;
lib_transform_coord( &x_axis[num_edge], &mid_axis, rot_mx ) ;
mid_axis.x = 0.0 ; mid_axis.y = 1.0 ; mid_axis.z = 0.0 ;
lib_create_rotate_matrix( rot_mx, X_AXIS, angle ) ;
lib_transform_coord( &y_axis[num_edge], &mid_axis, rot_mx ) ;
}
/* set up grid of points on +Z sphere surface */
for ( u_pol = 0 ; u_pol <= OUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol <= OUT_RESOLUTION ; ++v_pol ) {
CROSS( pt[u_pol][v_pol], x_axis[u_pol], y_axis[v_pol] ) ;
lib_normalize_coord3( &pt[u_pol][v_pol] ) ;
pt[u_pol][v_pol].w = 1.0 ;
}
}
for ( num_face = 0 ; num_face < 6 ; ++num_face ) {
/* transform points to cube face */
for ( u_pol = 0 ; u_pol <= OUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol <= OUT_RESOLUTION ; ++v_pol ) {
lib_rotate_cube_face( &pt[u_pol][v_pol]
, Z_AXIS
, num_face
) ;
}
}
/* output grid */
for ( u_pol = 0 ; u_pol < OUT_RESOLUTION ; ++u_pol ) {
for ( v_pol = 0 ; v_pol < OUT_RESOLUTION ; ++v_pol ) {
for ( num_tri = 0 ; num_tri < 2 ; ++num_tri ) {
for ( num_edge = 0 ; num_edge < 3 ; ++num_edge ) {
num_vert = (num_tri*2 + num_edge) % 4 ;
if ( num_vert == 0 ) {
u_vert = u_pol ;
v_vert = v_pol ;
}
else if ( num_vert == 1 ) {
u_vert = u_pol ;
v_vert = v_pol + 1 ;
}
else if ( num_vert == 2 ) {
u_vert = u_pol + 1 ;
v_vert = v_pol + 1 ;
}
else {
u_vert = u_pol + 1 ;
v_vert = v_pol ;
}
edge_pt[num_edge*6+3] = pt[u_vert][v_vert].x ;
edge_pt[num_edge*6+4] = pt[u_vert][v_vert].y ;
edge_pt[num_edge*6+5] = pt[u_vert][v_vert].z ;
edge_pt[num_edge*6+0] =
edge_pt[num_edge*6+3] * center_pt->w +
center_pt->x ;
edge_pt[num_edge*6+1] =
edge_pt[num_edge*6+4] * center_pt->w +
center_pt->y ;
edge_pt[num_edge*6+2] =
edge_pt[num_edge*6+5] * center_pt->w +
center_pt->z ;
}
polygon3d( fildes, edge_pt, 3, FALSE ) ;
}
}
}
}
}
int devopen(dev_kind,init_mode)
int dev_kind,init_mode;
{
char *dev, *driver;
int fildes ;
if ( dev_kind == OUTDEV ) {
dev = getenv("OUTDEV");
if (!dev) dev = default_outdev ;
driver = getenv("OUTDRIVER");
if (!driver) driver = default_outdriver ;
} else {
dev = getenv("INDEV");
if (!dev) dev = default_indev ;
driver = getenv("INDRIVER");
if (!driver) driver = default_indriver ;
}
fildes = gopen(dev,dev_kind,driver,init_mode);
return(fildes) ;
}
@EOF
chmod 644 lookonce.c
echo x - makefile
cat >makefile <<'@EOF'
# cc = C compiler
# -c compile only, do not try to link
# -g debug mode
# -O optimize
# -p monitor timing
# -Wc,-Yf use floating point numbers as themselves - don't convert
# this option has problems - not sure what to do
CC=cc -c -O
INC=def.h lib.h
BASELIB=-lm -lmalloc
all: lookat lookonce
lib.o: $(INC) lib.c
$(CC) lib.c
lookat: lib.o lookat.o
cc -o lookat lookat.o lib.o -lsbdl \
-ldd98721 -ldd98731 -lddhil -lsb1 -lsb2 $(BASELIB)
lookat.o: $(INC) lookat.c
$(CC) lookat.c
lookonce: lib.o lookonce.o
cc -o lookonce lookonce.o lib.o \
-ldd98721 -ldd98731 -lsb1 -lsb2 $(BASELIB)
lookonce.o: $(INC) lookonce.c
$(CC) lookonce.c
@EOF
chmod 644 makefile
echo x - pol005.nff
cat >pol005.nff <<'@EOF'
v
from 1.77033 1.52969 0.164572
at -0.258552 -0.643251 -2.17386
up 0 1 0
angle 20
hither 1
resolution 512 512
b 0.078 0.361 0.753
l 10 10 10
l 10 -8 -12
l -8 12 -10
l -12 -10 8
f 1 1 1 1 0 0 0 0
p 5
-0.636237 -0.993877 -2.45654
-0.193076 -0.100015 -2.38857
-0.0252202 -1.08063 -2.4897
-0.739978 -0.387826 -2.39404
0.248668 -0.528189 -2.44769
f 1 0.1 0.1 1 0 0 0 0
p 5
-0.193076 -0.100015 -2.38857
-0.636237 -0.993877 -2.45654
-0.491883 -0.205877 -1.85803
-0.282292 -0.587026 -2.75847
-0.765771 -0.758314 -1.90004
f 0 1 0.1 1 0 0 0 0
p 5
-0.0252202 -1.08063 -2.4897
-0.193076 -0.100015 -2.38857
0.222874 -0.898677 -1.95368
-0.282292 -0.587026 -2.75847
0.119134 -0.292626 -1.89118
f 0 0.1 1 1 0 0 0 0
p 5
-0.739978 -0.387826 -2.39404
-0.0252202 -1.08063 -2.4897
-0.765771 -0.758314 -1.90004
-0.282292 -0.587026 -2.75847
-0.324027 -1.18649 -1.95915
f 0 1 1 1 0 0 0 0
p 5
0.248668 -0.528189 -2.44769
-0.739978 -0.387826 -2.39404
0.119134 -0.292626 -1.89118
-0.282292 -0.587026 -2.75847
-0.491883 -0.205877 -1.85803
f 1 0.1 1 1 0 0 0 0
p 5
-0.636237 -0.993877 -2.45654
0.248668 -0.528189 -2.44769
-0.324027 -1.18649 -1.95915
-0.282292 -0.587026 -2.75847
0.222874 -0.898677 -1.95368
f 1 1 0.1 1 0 0 0 0
p 5
0.119134 -0.292626 -1.89118
-0.765771 -0.758314 -1.90004
0.222874 -0.898677 -1.95368
-0.491883 -0.205877 -1.85803
-0.324027 -1.18649 -1.95915
f 1 1 1 1 0 0 0 0
p 5
-0.765771 -0.758314 -1.90004
0.119134 -0.292626 -1.89118
-0.739978 -0.387826 -2.39404
-0.234811 -0.699477 -1.58925
-0.193076 -0.100015 -2.38857
f 1 0.1 0.1 1 0 0 0 0
p 5
0.222874 -0.898677 -1.95368
-0.765771 -0.758314 -1.90004
-0.0252202 -1.08063 -2.4897
-0.234811 -0.699477 -1.58925
-0.636237 -0.993877 -2.45654
f 0 1 0.1 1 0 0 0 0
p 5
-0.491883 -0.205877 -1.85803
0.222874 -0.898677 -1.95368
-0.193076 -0.100015 -2.38857
-0.234811 -0.699477 -1.58925
0.248668 -0.528189 -2.44769
f 0 0.1 1 1 0 0 0 0
p 5
-0.324027 -1.18649 -1.95915
-0.491883 -0.205877 -1.85803
-0.636237 -0.993877 -2.45654
-0.234811 -0.699477 -1.58925
-0.739978 -0.387826 -2.39404
f 0 1 1 1 0 0 0 0
p 5
0.119134 -0.292626 -1.89118
-0.324027 -1.18649 -1.95915
0.248668 -0.528189 -2.44769
-0.234811 -0.699477 -1.58925
-0.0252202 -1.08063 -2.4897
@EOF
chmod 644 pol005.nff
echo x - pol006.nff
cat >pol006.nff <<'@EOF'
v
from 5.65079 1.45769 2.28561
at 2.04071 -2.10085 -1.14963
up 0 1 0
angle 25
hither 1
resolution 512 512
b 0.078 0.361 0.753
l 10 10 10
l 10 -8 -12
l -8 12 -10
l -12 -10 8
f 1 1 1 1 0 0 0 0
p 5
1.4296 -1.42108 -1.41224
2.37642 -1.21122 -1.16835
2.94323 -1.99263 -1.42936
2.34671 -2.68543 -1.83457
1.41123 -2.33219 -1.82399
f 1 0.1 0.1 1 0 0 0 0
p 5
2.37642 -1.21122 -1.16835
1.4296 -1.42108 -1.41224
1.13819 -2.20908 -0.869896
1.90491 -2.48623 -0.290821
2.67018 -1.86951 -0.475274
f 0 1 0.1 1 0 0 0 0
p 5
2.94323 -1.99263 -1.42936
2.37642 -1.21122 -1.16835
1.7347 -1.51628 -0.464689
1.90491 -2.48623 -0.290821
2.65181 -2.78063 -0.887023
f 0 0.1 1 1 0 0 0 0
p 5
2.34671 -2.68543 -1.83457
2.94323 -1.99263 -1.42936
2.67018 -1.86951 -0.475274
1.90491 -2.48623 -0.290821
1.70499 -2.99049 -1.13091
f 0 1 1 1 0 0 0 0
p 5
1.41123 -2.33219 -1.82399
2.34671 -2.68543 -1.83457
2.65181 -2.78063 -0.887023
1.90491 -2.48623 -0.290821
1.13819 -2.20908 -0.869896
f 1 0.1 1 1 0 0 0 0
p 5
1.4296 -1.42108 -1.41224
1.41123 -2.33219 -1.82399
1.70499 -2.99049 -1.13091
1.90491 -2.48623 -0.290821
1.7347 -1.51628 -0.464689
f 1 1 0.1 1 0 0 0 0
p 5
2.65181 -2.78063 -0.887023
2.67018 -1.86951 -0.475274
1.7347 -1.51628 -0.464689
1.13819 -2.20908 -0.869896
1.70499 -2.99049 -1.13091
f 1 1 1 1 0 0 0 0
p 5
2.67018 -1.86951 -0.475274
2.65181 -2.78063 -0.887023
2.34671 -2.68543 -1.83457
2.17651 -1.71548 -2.00844
2.37642 -1.21122 -1.16835
f 1 0.1 0.1 1 0 0 0 0
p 5
1.7347 -1.51628 -0.464689
2.67018 -1.86951 -0.475274
2.94323 -1.99263 -1.42936
2.17651 -1.71548 -2.00844
1.4296 -1.42108 -1.41224
f 0 1 0.1 1 0 0 0 0
p 5
1.13819 -2.20908 -0.869896
1.7347 -1.51628 -0.464689
2.37642 -1.21122 -1.16835
2.17651 -1.71548 -2.00844
1.41123 -2.33219 -1.82399
f 0 0.1 1 1 0 0 0 0
p 5
1.70499 -2.99049 -1.13091
1.13819 -2.20908 -0.869896
1.4296 -1.42108 -1.41224
2.17651 -1.71548 -2.00844
2.34671 -2.68543 -1.83457
f 0 1 1 1 0 0 0 0
p 5
2.65181 -2.78063 -0.887023
1.70499 -2.99049 -1.13091
1.41123 -2.33219 -1.82399
2.17651 -1.71548 -2.00844
2.94323 -1.99263 -1.42936
@EOF
chmod 644 pol006.nff
echo x - tetra.nff
cat >tetra.nff <<'@EOF'
v
from 1.02285 -3.17715 -2.17451
at -0.004103 -0.004103 0.216539
up -0.816497 -0.816497 0.816497
angle 45
hither 1
resolution 512 512
b 0.078 0.361 0.753
l 1.87607 -18.1239 -5.00042
f 1 0.2 0.2 1 0 0 0 0
p 3
-1 -1 1
-1 -0.5 0.5
-0.5 -1 0.5
p 3
-0.5 -0.5 1
-0.5 -1 0.5
-1 -0.5 0.5
p 3
-0.5 -1 0.5
-0.5 -0.5 1
-1 -1 1
p 3
-1 -0.5 0.5
-1 -1 1
-0.5 -0.5 1
p 3
-1 -0.5 0.5
-1 0 0
-0.5 -0.5 0
p 3
-0.5 0 0.5
-0.5 -0.5 0
-1 0 0
p 3
-0.5 -0.5 0
-0.5 0 0.5
-1 -0.5 0.5
p 3
-1 0 0
-1 -0.5 0.5
-0.5 0 0.5
p 3
-0.5 -1 0.5
-0.5 -0.5 0
0 -1 0
p 3
0 -0.5 0.5
0 -1 0
-0.5 -0.5 0
p 3
0 -1 0
0 -0.5 0.5
-0.5 -1 0.5
p 3
-0.5 -0.5 0
-0.5 -1 0.5
0 -0.5 0.5
p 3
-0.5 -0.5 1
-0.5 0 0.5
0 -0.5 0.5
p 3
0 0 1
0 -0.5 0.5
-0.5 0 0.5
p 3
0 -0.5 0.5
0 0 1
-0.5 -0.5 1
p 3
-0.5 0 0.5
-0.5 -0.5 1
0 0 1
p 3
-1 0 0
-1 0.5 -0.5
-0.5 0 -0.5
p 3
-0.5 0.5 0
-0.5 0 -0.5
-1 0.5 -0.5
p 3
-0.5 0 -0.5
-0.5 0.5 0
-1 0 0
p 3
-1 0.5 -0.5
-1 0 0
-0.5 0.5 0
p 3
-1 0.5 -0.5
-1 1 -1
-0.5 0.5 -1
p 3
-0.5 1 -0.5
-0.5 0.5 -1
-1 1 -1
p 3
-0.5 0.5 -1
-0.5 1 -0.5
-1 0.5 -0.5
p 3
-1 1 -1
-1 0.5 -0.5
-0.5 1 -0.5
p 3
-0.5 0 -0.5
-0.5 0.5 -1
0 0 -1
p 3
0 0.5 -0.5
0 0 -1
-0.5 0.5 -1
p 3
0 0 -1
0 0.5 -0.5
-0.5 0 -0.5
p 3
-0.5 0.5 -1
-0.5 0 -0.5
0 0.5 -0.5
p 3
-0.5 0.5 0
-0.5 1 -0.5
0 0.5 -0.5
p 3
0 1 0
0 0.5 -0.5
-0.5 1 -0.5
p 3
0 0.5 -0.5
0 1 0
-0.5 0.5 0
p 3
-0.5 1 -0.5
-0.5 0.5 0
0 1 0
p 3
0 -1 0
0 -0.5 -0.5
0.5 -1 -0.5
p 3
0.5 -0.5 0
0.5 -1 -0.5
0 -0.5 -0.5
p 3
0.5 -1 -0.5
0.5 -0.5 0
0 -1 0
p 3
0 -0.5 -0.5
0 -1 0
0.5 -0.5 0
p 3
0 -0.5 -0.5
0 0 -1
0.5 -0.5 -1
p 3
0.5 0 -0.5
0.5 -0.5 -1
0 0 -1
p 3
0.5 -0.5 -1
0.5 0 -0.5
0 -0.5 -0.5
p 3
0 0 -1
0 -0.5 -0.5
0.5 0 -0.5
p 3
0.5 -1 -0.5
0.5 -0.5 -1
1 -1 -1
p 3
1 -0.5 -0.5
1 -1 -1
0.5 -0.5 -1
p 3
1 -1 -1
1 -0.5 -0.5
0.5 -1 -0.5
p 3
0.5 -0.5 -1
0.5 -1 -0.5
1 -0.5 -0.5
p 3
0.5 -0.5 0
0.5 0 -0.5
1 -0.5 -0.5
p 3
1 0 0
1 -0.5 -0.5
0.5 0 -0.5
p 3
1 -0.5 -0.5
1 0 0
0.5 -0.5 0
p 3
0.5 0 -0.5
0.5 -0.5 0
1 0 0
p 3
0 0 1
0 0.5 0.5
0.5 0 0.5
p 3
0.5 0.5 1
0.5 0 0.5
0 0.5 0.5
p 3
0.5 0 0.5
0.5 0.5 1
0 0 1
p 3
0 0.5 0.5
0 0 1
0.5 0.5 1
p 3
0 0.5 0.5
0 1 0
0.5 0.5 0
p 3
0.5 1 0.5
0.5 0.5 0
0 1 0
p 3
0.5 0.5 0
0.5 1 0.5
0 0.5 0.5
p 3
0 1 0
0 0.5 0.5
0.5 1 0.5
p 3
0.5 0 0.5
0.5 0.5 0
1 0 0
p 3
1 0.5 0.5
1 0 0
0.5 0.5 0
p 3
1 0 0
1 0.5 0.5
0.5 0 0.5
p 3
0.5 0.5 0
0.5 0 0.5
1 0.5 0.5
p 3
0.5 0.5 1
0.5 1 0.5
1 0.5 0.5
p 3
1 1 1
1 0.5 0.5
0.5 1 0.5
p 3
1 0.5 0.5
1 1 1
0.5 0.5 1
p 3
0.5 1 0.5
0.5 0.5 1
1 1 1
@EOF
chmod 644 tetra.nff
exit 0