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