#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'blurb.urt' <<'END_OF_FILE' X X THE UTAH RASTER TOOLKIT X XThe Utah Raster toolkit is a collection of programs and C routines for Xdealing with raster images commonly encountered in computer graphics. It Xprovides the following major functions: X X * A device and system independent image format for storing images X and information about them. Called the RLE format, it uses X run length encoding to reduce storage space for most images. X X * A library of C routines for reading, writing and manipulating X images stored in the RLE format. X X * A collections of programs for manipulating and displaying RLE X images. X X XThe Format: X X The device independent RLE file has two parts, the header, which stores X information about the image (size, position, channel information, X color maps, comments, etc), and the actual image data in a run length X encoded format. The RLE format often requires about a third of the X available space for most "image synthesis" style images. If the image X does not compress well, the RLE format stores it as straight pixel data X with little extra overhead. The format was first developed around X 1983 at the University of Utah. X XThe Library: X X C routines are provided for setting up and reading the image header, X and for reading and writing the image a scanline at a time. Images can X be read or written using two different methods. Using the "row" method, X the library performs the RLE encoding and decoding. With the "raw" method, X scanlines are constructed directly with RLE opcodes. Additional routines X are available for generating dither matrices (e.g., for display programs X running on devices with less than 24 bits of color). X XThe Tools: X applymap - Apply color map values to pixel values. X avg4 - Downfilter an image by 1/4, generating a matte channel if one X didn't previously exist X crop - Crop an image. X dvirle - Convert TeX output into anti-aliased images. X fant - Rotate and/or scale in image by an arbitrary (float) value. X mcut - Quantize an image from 24 to eight bits using the median cut X algorithm. X mergechan - Merge several channels from different files into a single X RLE file. X pyrmask - Blend images using Gaussian pyramids. X repos - Change the position in the RLE header. X rleClock - Generate an image of a clock. X rleaddcom - Add a comment to the RLE file's header. X rlebg - Generate a solid or variable background. X rlebox - Find the actual non-background area of an image. X rlecomp - Digital image compositor. Provides the operations over, atop, X in, out, xor, plus, minus and diff on two images. X rledither - Floyd-Steinberg to a given color map. X rleflip - Rotate an image by 90/180 degree increments. X rlehdr - Dump the contents of the RLE header in human readable form. X rlehisto - Generate the histogram of an RLE file. X rleldmap - Load a color map into an RLE file from a variety of sources. X rlemandl - Generate Mandlebrot sets as RLE files. X rlenoise - Adds random noise to an image. X rlepatch - Overlay several smaller images over a larger one. X rleprint - Print all pixel values. X rlequant - Variance-based color quantization. X rlescale - Generates gray scale and color scale RLE files. X rleselect - Select specific images from a file. X rlesetbg - Set the background color stored in the RLE header. X rleskel - A skeleton application, for rolling your own. X rlespiff - Simple contrast enhancement to "spiff up" images. X rlesplice - Splice images together horizontally or vertically. X rlesplit - Split a file containing several images into several files. X rleswap - Swap, copy or delete channels in an RLE file. X rlezoom - Enlarge or shrink an image with pixel replication. X smush - Perform a simple Gaussian filter on an image. X to8 - Convert a 24 bit RGB image to an eight bit dithered one. X tobw - Convert 24 bits to 8 bits black and white. X unexp - Convert an "exponential" image to a displayable one. X unslice - Quickly assemble an image from several horizontal strips X X Format conversion programs are provided for: X - Ascii (line printer pictures) (to) X - Cubicomp image format (from) X - GIF (to and from) X - MacPaint (to and from) X - PBMPLUS pgm (from) and ppm (to and from) X - PostScript (to) X - Sun rasterfiles (to and from) X - Targa image format (from) X - TIFF (to and from) X - Wasatch paint systems (from) X - Wavefront 'RLA' format (to and from) X - Simple pixel streams (color & B&W) (to and from) X X Display programs are provided for: X get4d - SGI Iris 4D workstation X get_orion - Orion displays X getap - Apollo workstations X getbob - HP Series 300 ("bobcat") running Windows 9000 X getcx3d - Chromatics CX1500 display X getfb - BRL "libfb" displays X getgmr - Grinnell GMR-27 (remember those?) X getiris - Iris in raw 24 bit mode. X getmac - Macintosh. X getmex - Iris running Mex X getqcr - Photograph images with the Matrix QCR-Z camera. X getren - HP 98721 "Renaissance" display X getsun - Suns running Suntools X getx10 - Workstations running the X10 window system X getx11 - Workstations running X11 X - [Note display programs for a particular device are X simple to add] X X All the tools are designed to pipe together, so they can be used as X filters on images much like the standard Unix tools filter text. X XPlus: X X The raster toolkit also includes Unix man pages for the library and X commands, some sample images, and additional documentation. X XSystem Requirements: X X We have successfully ported the Raster Toolkit to a number of Unix X systems, including 4.2/4.3bsd (Vax, Sun, etc), Apollo Domain/IX, HP X Series 300, SGI Iris, IBM RT and RS6000, Stardent GS-1000, Cray X running UNICOS. Display programs are included for several devices. X Creating display programs for additional devices is a X straightforward task. X XDistribution: X X For Internet sites, the toolkit may be obtained via anonymous FTP to X the sites listed below, in the file pub/urt-3.0.tar.Z. Some sample X images are in the file pub/urt-img.tar.Z, and the file X pub/urt-doc.tar.Z contains some (somewhat out-of-date) "papers" X describing the toolkit. We are still working out distribution X mechanisms for sites not connected to the Internet. We will X probably be adding other archive sites; please send mail to one of X the addresses below if you don't see a site near you (particularly X if you are on the other side of the Atlantic or Pacific). If you X would like to offer to be an archive site, please let us know, too. X X cs.utah.edu (128.110.4.21) X weedeater.math.yale.edu (130.132.23.17) X freebie.engin.umich.edu (35.2.68.23) X X Although the Raster Toolkit software is copyrighted, it may be freely X re-distributed on a "GNU-like" basis. X XIf you have further questions, please direct them to X toolkit-request@cs.utah.edu Xor urt-request@caen.engin.umich.edu X(but not both). END_OF_FILE if test 7019 -ne `wc -c <'blurb.urt'`; then echo shar: \"'blurb.urt'\" unpacked with wrong size! fi # end of 'blurb.urt' fi if test -f 'libray/liblight/shadow.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/liblight/shadow.c'\" else echo shar: Extracting \"'libray/liblight/shadow.c'\" \(7569 characters\) sed "s/^X//" >'libray/liblight/shadow.c' <<'END_OF_FILE' X/* X * shadow.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: shadow.c,v 4.0.1.1 1991/09/29 15:40:57 cek Exp cek $ X * X * $Log: shadow.c,v $ X * Revision 4.0.1.1 1991/09/29 15:40:57 cek X * patch1: ShadowOptions was incorrectly externed. X * X * Revision 4.0 91/07/17 14:35:34 kolb X * Initial version. X * X */ X#include "libobj/geom.h" X#include "libsurf/surface.h" X#include "light.h" X X/* X * Shadow stats. X * External functions have read access via ShadowStats(). X */ Xstatic unsigned long ShadowRays, ShadowHits, CacheMisses, CacheHits; X/* X * Options controlling how shadowing information is determined. X * Set by external modules via ShadowSetOptions(). X */ Xstatic long ShadowOptions; X Xvoid LightCacheHit(); X X/* X * Trace ray from point of intersection to a light. If an intersection X * occurs at a distance less than "dist" (the distance to the X * light source), then the point is in shadow, and TRUE is returned. X * Otherwise, the brightness/color of the light is computed ('result'), X * and FALSE is returned. X */ Xint XShadowed(result, color, cache, ray, dist, noshadow) XColor *result, *color; /* resultant intensity, light color */ XShadowCache *cache; /* shadow cache for light */ XRay *ray; /* ray, origin on surface, dir towards light */ XFloat dist; /* distance from pos to light source */ Xint noshadow; /* If TRUE, no shadow ray is cast. */ X{ X int i, smooth, enter; X HitList hitlist; X Ray tmpray; X ShadowCache *cp; X Vector hitpos, norm, gnorm; X Surface surf, *sptr, *prevsurf; X Float s, totaldist, statten; X Color res; X X if (noshadow || NOSHADOWS(ShadowOptions)) { X *result = *color; X return FALSE; X } X X ShadowRays++; X s = dist; X cp = &cache[ray->depth]; X /* X * Check shadow cache. SHADOWCACHE() is implied. X */ X if (cp->obj) { X /* X * Transform ray to the space of the cached primitive. X */ X tmpray = *ray; X if (cp->dotrans) X s *= RayTransform(&tmpray, &cp->trans); X /* X * s = distance to light source in 'primitive space'. X * Intersect ray with cached object. X */ X if (cp->obj->animtrans) { X /* X * Geom has animated transformation -- X * call intersect so that the transformation X * is resolved properly. X */ X if (intersect(cp->obj, &tmpray, &hitlist, X SHADOW_EPSILON, &s)) { X CacheHits++; X return TRUE; X } X } else if (IsAggregate(cp->obj)) { X if ((*cp->obj->methods->intersect)(cp->obj->obj, X &tmpray, &hitlist, SHADOW_EPSILON, &s)) { X CacheHits++; X return TRUE; X } X } else if ((*cp->obj->methods->intersect)(cp->obj->obj, X &tmpray, SHADOW_EPSILON, &s)) { X /* Hit cached object. */ X CacheHits++; X return TRUE; X } X /* X * Did not hit anything -- zero out the cache. X */ X CacheMisses++; X /* X * Transformed -- reset s for use below. X */ X s = dist; X cp->obj = (Geom *)NULL; X cp->dotrans = FALSE; X } X X hitlist.nodes = 0; X if (!TraceRay(ray, &hitlist, SHADOW_EPSILON, &s)) { X /* Shadow ray didn't hit anything. */ X *result = *color; X return FALSE; X } X X /* X * Otherwise, we've hit something. X */ X ShadowHits++; X X /* X * If we're not worrying about transparent objects... X * This is ugly due to the fact that we have to find X * the surface associated with the object that was hit. X * GetShadingSurf() will always return a non-null value. X * X * ***NOTE** X * The transparency of the surface is checked below without X * applying textures, if any, to it. This means that if X * an object may be made trasparent by a texture, its X * surface should have non-zero transparency *before* texturing X * as well. X */ X if (!SHADOWTRANSP(ShadowOptions)) { X if (SHADOWCACHE(ShadowOptions)) X LightCacheHit(&hitlist, cp); X return TRUE; X } X X /* X * We've hit a transparent object. Attenuate the color of the light X * source and continue the ray until we hit background or a X * non-transparent object. Note that this is incorrect if DefIndex or X * any of the indices of refraction of the surfaces differ. X */ X X totaldist = 0.; X prevsurf = (Surface *)NULL; X res = *color; X X do { X /* X * Get a pointer to the surface to be used X * for shading... X */ X sptr = GetShadingSurf(&hitlist); X if (sptr->transp < EPSILON) { X if (SHADOWCACHE(ShadowOptions)) X LightCacheHit(&hitlist, cp); X return TRUE; X } X /* X * Take specular transmission attenuation from X * previous intersection into account. X */ X if (prevsurf) { X if (prevsurf->statten != 1.) { X statten = pow(prevsurf->statten, s - totaldist); X ColorScale(statten, res, &res); X } X } X /* X * Perform texturing and the like in case surface X * transparency is modulated. X */ X /* copy the surface to be used... */ X surf = *sptr; X enter = ComputeSurfProps(&hitlist, ray, &hitpos, X &norm, &gnorm, &surf, &smooth); X if (enter) X prevsurf = &surf; X else X prevsurf = (Surface *)NULL; X /* X * Attenuate light source by body color of surface. X */ X ColorScale(surf.transp, res, &res); X ColorMultiply(res, surf.body, &res); X /* X * Return if attenuation becomes large. X * In this case, the light was attenuated to nothing, X * so we can't cache anything... X */ X if (res.r < EPSILON && res.g < EPSILON && res.b < EPSILON) X return TRUE; X /* X * Min distance is previous max. X */ X totaldist = s + EPSILON; X /* X * Max distance is dist to light source X */ X s = dist; X /* X * Trace ray starting at new origin and in the X * same direction. X */ X hitlist.nodes = 0; X } while (TraceRay(ray, &hitlist, totaldist, &s)); X X *result = res; X return FALSE; X} X Xvoid XShadowStats(shadowrays, shadowhit, cachehit, cachemiss) Xunsigned long *shadowrays, *shadowhit, *cachehit, *cachemiss; X{ X *shadowrays = ShadowRays; X *shadowhit = ShadowHits; X *cachehit = CacheHits; X *cachemiss = CacheMisses; X} X Xvoid XShadowSetOptions(options) Xlong options; X{ X ShadowOptions = options; X} X Xvoid XLightCacheHit(hitlist, cache) XHitList *hitlist; XShadowCache *cache; X{ X HitNode *np; X int i, n; X extern long ShadowOptions; X X i = 0; X X if (SHADOWCSG(ShadowOptions)) { X /* X * There's possibly a CSG object in the X * hitlist, so we can't simply cache the X * primitive that was hit. Find the X * object lowest in hit that's not part X * of a CSG object, and cache it. X */ X i = FirstCSGGeom(hitlist); X } X X if (SHADOWBLUR(ShadowOptions)) { X /* X * Something might be animated -- X * gotta cache the puppy. X */ X n = FirstAnimatedGeom(hitlist); X if (n > i) X i = n; X } X X /* X * Compute total world-->cached object X * transformation and store in cache->trans. X */ X /* X * Find the first transformation... X */ X np = &hitlist->data[i]; X cache->obj = np->obj; X /* X * If the cached object is animated, then we don't X * want to include the object's transformation(s) X * in cache->trans (it's taken care of in shadowed() X * by calling intersect). X */ X if (cache->obj->animtrans) { X i++; X np++; X } X cache->dotrans = FALSE; X while (i < hitlist->nodes -1) { X if (np->obj->trans) { X if (cache->dotrans) { X MatrixMult( X &np->obj->trans->itrans, X &cache->trans, X &cache->trans); X } else { X MatrixCopy( X &np->obj->trans->itrans, X &cache->trans); X cache->dotrans = TRUE; X } X } X i++; X np++; X } X} END_OF_FILE if test 7569 -ne `wc -c <'libray/liblight/shadow.c'`; then echo shar: \"'libray/liblight/shadow.c'\" unpacked with wrong size! fi # end of 'libray/liblight/shadow.c' fi if test -f 'libray/libobj/poly.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libray/libobj/poly.c'\" else echo shar: Extracting \"'libray/libobj/poly.c'\" \(7872 characters\) sed "s/^X//" >'libray/libobj/poly.c' <<'END_OF_FILE' X/* X * poly.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: poly.c,v 4.0 91/07/17 14:39:00 kolb Exp Locker: kolb $ X * X * $Log: poly.c,v $ X * Revision 4.0 91/07/17 14:39:00 kolb X * Initial version. X * X */ X#include "geom.h" X#include "poly.h" X Xstatic Methods *iPolygonMethods = NULL; Xstatic char polyName[] = "polygon"; X Xunsigned long PolyTests, PolyHits; X X/* X * Create a reference to a polygon with vertices equal to those X * on the linked-list "plist." X */ XPolygon * XPolygonCreate(plist, npoints, flipflag) XPointList *plist; Xint npoints, flipflag; X{ X Polygon *poly; X Float indexval; X Vector *prev, *cur, anorm; X PointList *curp, *pltmp; X int i; X X poly = (Polygon *)share_malloc(sizeof(Polygon)); X /* X * Allocate space for the vertices. X */ X poly->points = (Vector *)Malloc((unsigned)(npoints*sizeof(Vector))); X poly->npoints = npoints; X X /* X * Copy the vertices from the linked list to the array, freeing X * the linked list as we go so that the caller doesn't have X * to worry about doing so. X */ X i = npoints -1; X for(curp = plist; curp != (PointList *)0; curp = pltmp) { X poly->points[i--] = curp->vec; X pltmp = curp->next; X free((voidstar)curp); X } X X /* X * Find normal to polygon. X */ X poly->norm.x = poly->norm.y = poly->norm.z = 0.; X prev = &poly->points[poly->npoints -1]; X for(i = 0,cur = poly->points;i < poly->npoints;i++, prev = cur, cur++) { X poly->norm.x += (prev->y - cur->y) * (prev->z + cur->z); X poly->norm.y += (prev->z - cur->z) * (prev->x + cur->x); X poly->norm.z += (prev->x - cur->x) * (prev->y + cur->y); X } X X if (VecNormalize(&poly->norm) == 0.) { X /* X * Degenerate normal --> degenerate polygon X */ X RLerror(RL_WARN, "Degenerate polygon.\n"); X free((voidstar)poly->points); X return (Polygon *)NULL; X } X X /* X * If filflag is true, flip the normal. X */ X if (flipflag) X VecScale(-1, poly->norm, &poly->norm); X X /* X * Compute and store the plane constant. X */ X poly->d = dotp(&poly->norm, &poly->points[0]); X X /* X * Find the "dominant" part of the normal vector. This X * is used to turn the point-in-polygon test into a 2D problem. X */ X anorm.x = fabs(poly->norm.x); X anorm.y = fabs(poly->norm.y); X anorm.z = fabs(poly->norm.z); X indexval = max(anorm.y, anorm.z); X indexval = max(anorm.x, indexval); X X if (indexval == anorm.x) X poly->index = XNORMAL; X else if (indexval == anorm.y) X poly->index = YNORMAL; X else X poly->index = ZNORMAL; X X return poly; X} X XMethods * XPolygonMethods() X{ X if (iPolygonMethods == (Methods *)NULL) { X iPolygonMethods = MethodsCreate(); X iPolygonMethods->create = (GeomCreateFunc *)PolygonCreate; X iPolygonMethods->methods = PolygonMethods; X iPolygonMethods->name = PolygonName; X iPolygonMethods->intersect = PolygonIntersect; X iPolygonMethods->normal = PolygonNormal; X iPolygonMethods->uv = PolygonUV; X iPolygonMethods->bounds = PolygonBounds; X iPolygonMethods->stats = PolygonStats; X iPolygonMethods->checkbounds = TRUE; X iPolygonMethods->closed = FALSE; X } X return iPolygonMethods; X} X X/* X * Quadrants are defined as: X * | X * 1 | 0 X * | X * -------c-------- X * | X * 2 | 3 X * | X */ X#define quadrant(p, c) ((p.upos; X dir = ray->dir; X /* X * First, find where ray hits polygon plane, projecting X * along the polygon's dominant normal component. X */ X X dist = dotp(&poly->norm, &dir); X if(fabs(dist) < EPSILON) X /* X * No intersection with polygon plane. X */ X return FALSE; X X dist = (poly->d - dotp(&poly->norm, &pos)) / dist; X if(dist < mindist || dist > *maxdist) X /* X * Intersection point behind origin or too far. X */ X return FALSE; X X /* X * Compute the point of intersection, projected appropriately. X */ X if(poly->index == XNORMAL) { X center.u = pos.y + dist * dir.y; X center.v = pos.z + dist * dir.z; X } else if(poly->index == YNORMAL) { X center.v = pos.z + dist * dir.z; X center.u = pos.x + dist * dir.x; X } else { X center.u = pos.x + dist * dir.x; X center.v = pos.y + dist * dir.y; X } X X /* X * Is the point inside the polygon? X * X * Compute the winding number by finding the quadrant each X * polygon point lies in with respect to the the point in X * question, and computing a "delta" (winding number). If we X * end up going around in a complete circle around X * the point (winding number is non-zero at the end), then X * we're inside. Otherwise, the point is outside. X * X * Note that we can turn this into a 2D problem by projecting X * all the points along the axis defined by poly->index, X * the "dominant" part of the polygon's normal vector. X */ X winding = 0; X VecProject(last, poly->points[poly->npoints -1], poly->index); X lastquad = quadrant(last, center); X for(i = 0; i < poly->npoints; i++, last = cur) { X VecProject(cur, poly->points[i], poly->index); X quad = quadrant(cur, center); X if (quad == lastquad) X continue; X if(((lastquad + 1) & 3) == quad) X winding++; X else if(((quad + 1) & 3) == lastquad) X winding--; X else { X /* X * Find where edge crosses X * center's X axis. X */ X right = last.u - cur.u; X left = (last.v - cur.v) * (center.u - last.u); X if(left + last.v * right > right * center.v) X winding += 2; X else X winding -= 2; X } X lastquad = quad; X } X X if (winding != 0) { X *maxdist = dist; X PolyHits++; X return TRUE; X } X return FALSE; X} X X/* X * Return the normal to the polygon surface. X */ X/*ARGSUSED*/ Xint XPolygonNormal(poly, pos, nrm, gnrm) XPolygon *poly; XVector *pos, *nrm, *gnrm; X{ X *gnrm = *nrm = poly->norm; X return FALSE; X} X X/*ARGSUSED*/ Xvoid XPolygonUV(poly, pos, norm, uv, dpdu, dpdv) XPolygon *poly; XVector *pos, *norm, *dpdu, *dpdv; XVec2d *uv; X{ X /* X * Since there's no nice way to do this, we wimp out and X * do the following... X * X * Of course, we could force the user to specify U and V X * axes, but forcing them to use X and Y as U and V is X * just as arbitrary and much simpler to deal with. X */ X uv->u = pos->x; X uv->v = pos->y; X if (dpdu) { X dpdu->x = 1.; X dpdu->y = dpdu->z = 0.; X dpdv->x = dpdv->z = 0.; X dpdv->y = 1.; X } X} X X/* X * Compute the extent of a polygon X */ Xvoid XPolygonBounds(poly, bounds) XPolygon *poly; XFloat bounds[2][3]; X{ X register int i; X X bounds[LOW][X] = bounds[HIGH][X] = poly->points[0].x; X bounds[LOW][Y] = bounds[HIGH][Y] = poly->points[0].y; X bounds[LOW][Z] = bounds[HIGH][Z] = poly->points[0].z; X X for (i = 1 ;i < poly->npoints; i++) { X if (poly->points[i].x < bounds[LOW][X]) X bounds[LOW][X] = poly->points[i].x; X if (poly->points[i].x > bounds[HIGH][X]) X bounds[HIGH][X] = poly->points[i].x; X if (poly->points[i].y < bounds[LOW][Y]) X bounds[LOW][Y] = poly->points[i].y; X if (poly->points[i].y > bounds[HIGH][Y]) X bounds[HIGH][Y] = poly->points[i].y; X if (poly->points[i].z < bounds[LOW][Z]) X bounds[LOW][Z] = poly->points[i].z; X if (poly->points[i].z > bounds[HIGH][Z]) X bounds[HIGH][Z] = poly->points[i].z; X } X} X Xchar * XPolygonName() X{ X return polyName; X} X Xvoid XPolygonStats(tests, hits) Xunsigned long *tests, *hits; X{ X *tests = PolyTests; X *hits = PolyHits; X} X Xvoid XPolygonMethodRegister(meth) XUserMethodType meth; X{ X if (iPolygonMethods) X iPolygonMethods->user = meth; X} END_OF_FILE if test 7872 -ne `wc -c <'libray/libobj/poly.c'`; then echo shar: \"'libray/libobj/poly.c'\" unpacked with wrong size! fi # end of 'libray/libobj/poly.c' fi if test -f 'libshade/picture.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libshade/picture.c'\" else echo shar: Extracting \"'libshade/picture.c'\" \(7560 characters\) sed "s/^X//" >'libshade/picture.c' <<'END_OF_FILE' X/* X * picture.c X * X * Copyright (C) 1989, 1991, Craig E. Kolb, Rod G. Bogart X * All rights reserved. X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: picture.c,v 4.0 91/07/17 14:47:00 kolb Exp Locker: kolb $ X * X * $Log: picture.c,v $ X * Revision 4.0 91/07/17 14:47:00 kolb X * Initial version. X * X */ X#include "rayshade.h" X#include "picture.h" X#include "viewing.h" X#include "options.h" X#include "stats.h" X X#ifdef URT Xunsigned char **outptr; /* Output buffer */ Xstatic int count_rle_rows(); X#endif X X/* X * Convert floating-point (0.-1.) to unsigned char (0-255), with no gamma X * correction. X */ Xunsigned char Xcorrect(x) XFloat x; X{ X /* X * Truncate values < 0 or > 1. X */ X if (x < 0) X return 0; X if (x > 1.) X return 255; X return (unsigned char)(x * 255.); X} X X#ifdef URT X/* X * Open image file and write RLE header. X */ Xvoid XPictureStart(argv) Xchar **argv; X{ X char gammacom[40]; X X if (Options.framenum != Options.startframe) { X /* X * We've been here before; X * write a new header and return. X */ X rle_put_setup(&rle_dflt_hdr); X return; X } X /* X * If Appending, then we know that outfile is valid, 'cause X * we've already read its header. X */ X if (Options.appending) { X Options.pictfile = fopen(Options.imgname, "a"); X if (Options.pictfile == (FILE *)0) X RLerror(RL_PANIC, "Cannot append to %s?!\n", X Options.imgname); X rle_dflt_hdr.rle_file = Options.pictfile; X rle_put_init(&rle_dflt_hdr); X } else { X /* X * Starting image from scatch. X */ X if (Options.imgname) { X Options.pictfile = fopen(Options.imgname, "w"); X if (Options.pictfile == (FILE *)NULL) X RLerror(RL_PANIC,"Cannot open %s for writing.", X Options.imgname); X } else X Options.pictfile = stdout; X X rle_dflt_hdr.xmax = Screen.maxx; X rle_dflt_hdr.ymax = Screen.maxy; X rle_dflt_hdr.xmin = Screen.minx; X rle_dflt_hdr.ymin = Screen.miny; X rle_dflt_hdr.alpha = Options.alpha; X if (Options.alpha) X RLE_SET_BIT(rle_dflt_hdr, RLE_ALPHA); X if (Options.exp_output) { X RLE_SET_BIT(rle_dflt_hdr, RLE_BLUE + 1); X rle_dflt_hdr.ncolors = 4; X rle_putcom("exponential_data", &rle_dflt_hdr); X } X else X rle_dflt_hdr.ncolors = 3; X /* X * Document image gamma in RLE comment area. X * Options.gamma has been inverted. X */ X (void)sprintf(gammacom, "display_gamma=%g", 1./Options.gamma); X rle_putcom(gammacom, &rle_dflt_hdr); X /* X * Document command line in RLE history. X */ X rle_addhist(argv, (rle_hdr *)0, &rle_dflt_hdr); X rle_dflt_hdr.rle_file = Options.pictfile; X rle_put_setup(&rle_dflt_hdr); X /* X * Flush the header. If we don't, and LINDA forks off X * a bunch of workers, strange things will happen (they'll X * all flush the buffer when they die, and you end up with X * lots of headers at the end of the file). X */ X (void)fflush(rle_dflt_hdr.rle_file); X } X X if (rle_row_alloc(&rle_dflt_hdr, &outptr) < 0) X RLerror(RL_PANIC, "Unable to allocate image memory.\n"); X} X X/* X * Read RLE header to which we are appending in order determine X * old resolution, window location, and the like. X */ Xvoid XPictureSetWindow() X{ X if (Options.imgname == (char *)NULL) X RLerror(RL_PANIC, X "No partially-completed image file specified.\n"); X X /* X * Open image and read RLE header. X */ X Options.pictfile = fopen(Options.imgname, "r"); X rle_dflt_hdr.rle_file = Options.pictfile; X rle_get_setup_ok(&rle_dflt_hdr, "rayshade", Options.imgname); X X /* X * If user specified a window that does not match what's in X * the header, complain. X if (Screen.minx != UNSET && Screen.minx != rle_dflt_hdr.xmin || X Screen.miny != UNSET && Screen.miny != rle_dflt_hdr.ymin || X Screen.maxx != UNSET && Screen.maxx != rle_dflt_hdr.xmax || X Screen.maxy != UNSET && Screen.maxy != rle_dflt_hdr.ymax) X RLerror(RL_ADVISE, "Image window: %d - %d, %d - %d.\n", X rle_dflt_hdr.xmin, rle_dflt_hdr.xmax, X rle_dflt_hdr.ymin, rle_dflt_hdr.ymax); X */ X /* X * Set window. X */ X Screen.minx = rle_dflt_hdr.xmin; X Screen.miny = rle_dflt_hdr.ymin; X Screen.maxx = rle_dflt_hdr.xmax; X Screen.maxy = rle_dflt_hdr.ymax; X X /* X * Set alpha. Warn the user if the alpha option doesn't reflect X * what's already been rendered. X */ X if (Options.alpha != rle_dflt_hdr.alpha) X RLerror(RL_WARN, "Image %s %s an alpha channel.\n", X Options.imgname, X rle_dflt_hdr.alpha ? "has" : "does not have"); X X Options.alpha = rle_dflt_hdr.alpha; X X /* X * Determine number of scanlines written to file. X */ X Screen.miny += count_rle_rows(&rle_dflt_hdr); X if (Screen.miny >= Screen.maxy) { X fprintf(stderr, "\"%s\" is a complete image.\n", X Options.imgname); X exit(0); X } X fprintf(Stats.fstats,"Continuing \"%s\" at scanline #%d.\n", X Options.imgname, Screen.miny); X (void)fclose(Options.pictfile); X} X Xstatic int Xcount_rle_rows( hdr ) Xrle_hdr *hdr; X{ X rle_op **raw; X int **nraw, y, ynext; X X if (rle_raw_alloc( hdr, &raw, &nraw ) < 0) { X RLerror(RL_PANIC, X "Unable to allocate memory in count_rle_rows.\n"); X } X X y = hdr->ymin; X while ((ynext = rle_getraw( hdr, raw, nraw )) != 32768) { X y = ynext+1; X rle_freeraw( hdr, raw, nraw ); X } X X /* Free memory. */ X rle_raw_free( hdr, raw, nraw ); X X return y - hdr->ymin; X} X X/* X * Write a scanline of output. X * "buf" is an array of Color structures of size Screen.xsize. Each color X * component is normalized to [0, 1.]. X */ Xvoid XPictureWriteLine(buf) XPixel *buf; X{ X register int i, chan; X float floats[3]; X rle_pixel pixels[4]; X X for(i = 0; i < Screen.xsize; i++) { X if (!Options.exp_output) { X /* X * Scale colors to fit unsigned char and check for X * over/underflow. X */ X outptr[0][i] = CORRECT(buf[i].r); X outptr[1][i] = CORRECT(buf[i].g); X outptr[2][i] = CORRECT(buf[i].b); X } else { X /* X * Convert 3 floats to 4 unsigned chars for X * 'exponential_data' RLE file. X */ X floats[0] = GAMMACORRECT(buf[i].r); X floats[1] = GAMMACORRECT(buf[i].g); X floats[2] = GAMMACORRECT(buf[i].b); X float_to_exp( 3, floats, pixels ); X for (chan = 0; chan <= 3; chan++) X outptr[chan][i] = pixels[chan]; X } X if (Options.alpha) X /* X * Don't gamma correct alpha channel. X */ X outptr[-1][i] = correct(buf[i].alpha); X } X rle_putrow(outptr, Screen.xsize, &rle_dflt_hdr); X} X X/* X * End the frame. X */ Xvoid XPictureFrameEnd() X{ X rle_puteof(&rle_dflt_hdr); X} X X/* X * Close image file. X */ Xvoid XPictureEnd() X{ X (void)fclose(Options.pictfile); X} X X#else /* !URT */ Xvoid XPictureStart(argv) Xchar **argv; X{ X if (Options.imgname) { X Options.pictfile = fopen(Options.imgname, "w"); X if (Options.pictfile == (FILE *)NULL) X RLerror(RL_PANIC, "Cannot open %s for writing.", X Options.imgname); X } else X Options.pictfile = stdout; X X fprintf(Options.pictfile,"%d %d\n",Screen.xsize, Screen.ysize); X X (void)fflush(Options.pictfile); X} X Xvoid XPictureWriteLine(buf) XPixel *buf; X{ X register int i; X X for (i = 0; i < Screen.xsize; i++) { X (void)fputc((int)CORRECT(buf[i].r), Options.pictfile); X (void)fputc((int)CORRECT(buf[i].g), Options.pictfile); X (void)fputc((int)CORRECT(buf[i].b), Options.pictfile); X } X (void)fflush(Options.pictfile); X} X Xvoid XPictureFrameEnd() X{ X /* X * Don't do anything -- generic format has no end-of-image marker. X */ X} X Xvoid XPictureEnd() X{ X (void)fclose(Options.pictfile); X} X X#endif /* URT */ END_OF_FILE if test 7560 -ne `wc -c <'libshade/picture.c'`; then echo shar: \"'libshade/picture.c'\" unpacked with wrong size! fi # end of 'libshade/picture.c' fi if test -f 'raypaint/xgraphics.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'raypaint/xgraphics.c'\" else echo shar: Extracting \"'raypaint/xgraphics.c'\" \(7806 characters\) sed "s/^X//" >'raypaint/xgraphics.c' <<'END_OF_FILE' X/* X * xgraphics.c X * X * Copyright (C) 1989, 1991 Craig E. Kolb, Rod G. Bogart X * X * This software may be freely copied, modified, and redistributed X * provided that this copyright notice is preserved on all copies. X * X * You may not distribute this software, in whole or in part, as part of X * any commercial product without the express consent of the authors. X * X * There is no warranty or other guarantee of fitness of this software X * for any purpose. It is provided solely "as is". X * X * $Id: xgraphics.c,v 4.0 91/07/17 17:37:32 kolb Exp Locker: kolb $ X * X * $Log: xgraphics.c,v $ X * Revision 4.0 91/07/17 17:37:32 kolb X * Initial version. X * X */ X X#include X#include X#include X#include X Xchar *display_name = NULL; XDisplay *dpy = NULL; XScreen *scrn; XVisual *vis; XColormap cmap; XGC gc; XWindow win; Xint screen_height; X Xunsigned long graymap[256]; Xint max_colors; Xdouble one_over_gamma = 0.4; X X/***************************************************************** X * Sets the gray color map for the device. A 2.5 gamma map is used X * by default. X */ Xsetup_gray_gamma_map() X{ X int cc, col; X int gamma_color; X X XColor xcolor; X X /* Use the default colormap if possible. */ X if ( vis == DefaultVisualOfScreen( scrn ) ) X cmap = DefaultColormapOfScreen( scrn ); X else X cmap = XCreateColormap( dpy, RootWindowOfScreen( scrn ), X vis, AllocNone ); X X /* try to share with current colormap */ X for (max_colors = 256; max_colors >= 16; max_colors = max_colors >> 1) { X xcolor.flags= DoRed | DoGreen | DoBlue; X for(col=0; col < max_colors; col++) { X gamma_color = (pow((float) col / (float) max_colors, X one_over_gamma) * 65536); X xcolor.red= gamma_color; X xcolor.green= gamma_color; X xcolor.blue= gamma_color; X if (!XAllocColor(dpy, cmap, &xcolor)) { X for (cc=0; cc < col; cc++) X XFreeColors(dpy, cmap, &graymap[cc], 1, 0); X col = 0; X break; X } X graymap[col] = xcolor.pixel; X } X if (col) X return; X } X X /* use new map */ X cmap = XCreateColormap( dpy, RootWindowOfScreen( scrn ), X vis, AllocNone ); X if (cmap == NULL) { X fprintf(stderr, "Could not create color map for visual\n"); X exit(-2); X } X for(cc=0; cc < 256; cc++) X if (!XAllocColorCells(dpy, cmap, False, NULL, 0, &graymap[cc], 1)) X break; X max_colors = cc; X X xcolor.flags= DoRed | DoGreen | DoBlue; X for(col=0; col < max_colors; col++) { X xcolor.pixel= graymap[col]; X gamma_color = (pow((float) col / (float) max_colors, X one_over_gamma) * 65536); X xcolor.red= gamma_color; X xcolor.green= gamma_color; X xcolor.blue= gamma_color; X XStoreColor(dpy, cmap, &xcolor); X } X} X XGraphicsInit(xsize, ysize, name) Xint xsize, ysize; Xchar *name; X{ X int win_size; X XSetWindowAttributes attrs; X XSizeHints sh; X X /* Open the display. */ X if ( ! dpy ) X { X XVisualInfo vis_temp, *vis_list, *max_vis; X int n_ret, i; X X dpy = XOpenDisplay( display_name ); X if ( ! dpy ) X { X fprintf( stderr, "rayview: Can't open display %s\n", X XDisplayName( display_name ) ); X exit(1); X } X X /* Get a PseudoColor visual that has the maximum number of planes. */ X vis_temp.class = PseudoColor; X vis_list = XGetVisualInfo( dpy, VisualClassMask, &vis_temp, &n_ret ); X if ( n_ret == 0 ) X { X fprintf(stderr, X "Can't find any PseudoColor visual from display %s.\n", X XDisplayName( display_name )); X exit(1); X } X max_vis = &vis_list[0]; X for ( i = 1; i < n_ret; i++ ) X { X if ( max_vis->depth < vis_list[i].depth ) X max_vis = &vis_list[i]; X } X vis = max_vis->visual; X scrn = ScreenOfDisplay( dpy, max_vis->screen ); X gc = DefaultGCOfScreen( scrn ); X X setup_gray_gamma_map(); X X XFree( (char *)vis_list ); X } X X screen_height = ysize; X X attrs.backing_store = Always; X attrs.colormap = cmap; X attrs.event_mask = ExposureMask; X attrs.background_pixel = BlackPixelOfScreen(scrn); X attrs.border_pixel = WhitePixelOfScreen(scrn); X X win = XCreateWindow( dpy, RootWindowOfScreen( scrn ), X 0, 0, xsize, ysize, 2, X 0, 0, vis, X CWBackingStore | CWColormap | CWEventMask | X CWBackPixel | CWBorderPixel, X &attrs ); X X sh.flags = PSize | PMinSize | PMaxSize; X sh.width = sh.min_width = sh.max_width = xsize; X sh.height = sh.min_height = sh.max_height = ysize; X XSetStandardProperties( dpy, win, name, name, None, NULL, 0, &sh ); X X XMapWindow( dpy, win ); X X XFlush( dpy ); X} X X/* X * Draw the pixel at (xp, yp) in the color given by the rgb-triple, X * 0 indicating 0 intensity, 255 max intensity. X */ XGraphicsDrawPixel(xp, yp, color) Xint xp, yp; Xunsigned char color[3]; X{ X float bwvalue; X int val; X X bwvalue = ( 0.35*color[0] + 0.55*color[1] + 0.10*color[2] ) / 256.0; X val = (int) ( bwvalue * max_colors ); X XSetForeground( dpy, gc, graymap[val] ); X XFillRectangle( dpy, win, gc, xp, (screen_height - (yp + 1)), X 1, 1 ); X} X X/* X * Draw the rect with lower left corner (xp, yp) and upper right X * corner (xp+ys, yp+ys). The colors of the l-l, l-r, u-r, and u-l X * corners are given as arrays of unsigned chars as above. X */ XGraphicsDrawRectangle(xp, yp, xs, ys, ll, lr, ur, ul) Xint xp, yp, xs, ys; Xunsigned char ll[3], lr[3], ur[3], ul[3]; X{ X float bwvalue; X int val; X X bwvalue = ( 0.35*ll[0] + 0.55*ll[1] + 0.10*ll[2] ) / 256.0; X val = (int) ( bwvalue * max_colors ); X XSetForeground( dpy, gc, graymap[val] ); X XFillRectangle( dpy, win, gc, xp, (screen_height - (yp + ys + 1)), X xs+1, ys+1 ); X XFlush( dpy ); X} X XGraphicsLeftMouseEvent() X{ X Window root_ret, child_ret; X int rx, ry, wx, wy; X unsigned int mask; X X if (XQueryPointer(dpy, win, &root_ret, &child_ret, X &rx, &ry, &wx, &wy, &mask)) { X return mask & Button1Mask; X } X else X return 0; X} X XGraphicsMiddleMouseEvent() X{ X Window root_ret, child_ret; X int rx, ry, wx, wy; X unsigned int mask; X X if (XQueryPointer(dpy, win, &root_ret, &child_ret, X &rx, &ry, &wx, &wy, &mask)) { X return mask & Button2Mask; X } X else X return 0; X} X XGraphicsRightMouseEvent() X{ X Window root_ret, child_ret; X int rx, ry, wx, wy; X unsigned int mask; X X if (XQueryPointer(dpy, win, &root_ret, &child_ret, X &rx, &ry, &wx, &wy, &mask)) { X return mask & Button3Mask; X } X else X return 0; X} X XGraphicsGetMousePos(x, y) Xint *x, *y; X{ X Window root_ret, child_ret; X int rx, ry, wx, wy; X unsigned int mask; X X if (XQueryPointer(dpy, win, &root_ret, &child_ret, X &rx, &ry, &wx, &wy, &mask)) { X *x = wx; X *y = screen_height - wy - 1; X } X else { X *x = 0; X *y = 0; X } X} X XGraphicsRedraw() X{ X XEvent event; X if (XCheckTypedEvent(dpy, Expose, &event)) { X XSetForeground( dpy, gc, graymap[0] ); X XFillRectangle( dpy, win, gc, event.xexpose.x, event.xexpose.y, X event.xexpose.width, event.xexpose.height ); X XFlush( dpy ); X return 1; X } X else X return 0; X} X END_OF_FILE if test 7806 -ne `wc -c <'raypaint/xgraphics.c'`; then echo shar: \"'raypaint/xgraphics.c'\" unpacked with wrong size! fi # end of 'raypaint/xgraphics.c' fi if test -f 'rayview/spheregen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rayview/spheregen.c'\" else echo shar: Extracting \"'rayview/spheregen.c'\" \(7060 characters\) sed "s/^X//" >'rayview/spheregen.c' <<'END_OF_FILE' X/* X * Routines to define a unit sphere Object. X * If you have a sphere library (-lsphere on most SGI machines), you can X * use that by defining SPHERELIB on the cc command line. Otherwise, X * we use Jon Leech's code to generate a sphere. X * C. Kolb 6/91 X */ X#ifdef SPHERELIB X#include X X/* X * Define unit sphere Object. Here, we make use of sgi's spherelib. X * If not available, undefine SPHERELIB, and the code below will be used. X */ XObject XGLSphereObjectDefine() X{ X int sphere; X X sphere = genobj(); X sphobj(sphere); X return sphere; X} X#else X X/* X * The following code has been slightly modified. The original sphere X * code is available via anonymous X * ftp from weedeater.math.yale.edu (130.132.23.17) in pub/sphere.c X * X * Modifications include changing print_triangle to draw a GL object, X * the inclusion of gl.h, X * the renaming of main() to GLSphereObjectDefine(), the nuking of anything X * phigs-related, and setting the ccw flag to be true. X * X * C. Kolb 6/91 X */ X X/*% cc -g sphere.c -o sphere -lm X * X * sphere - generate a triangle mesh approximating a sphere by X * recursive subdivision. First approximation is an octahedron; X * each level of refinement increases the number of triangles by X * a factor of 4. X * Level 3 (128 triangles) is a good tradeoff if gouraud X * shading is used to render the database. X * X * Usage: sphere [level] [-p] [-c] X * level is an integer >= 1 setting the recursion level (default 1). X * -p causes generation of a PPHIGS format ASCII archive X * instead of the default generic output format. X * -c causes triangles to be generated with vertices in counterclockwise X * order as viewed from the outside in a RHS coordinate system. X * The default is clockwise order. X * X * The subroutines print_object() and print_triangle() should X * be changed to generate whatever the desired database format is. X * X * Jon Leech (leech@cs.unc.edu) 3/24/89 X */ X#include X#include X X#include X Xtypedef struct { X double x, y, z; X} point; X Xtypedef struct { X point pt[3]; /* Vertices of triangle */ X double area; /* Unused; might be used for adaptive subdivision */ X} triangle; X Xtypedef struct { X int npoly; /* # of triangles in object */ X triangle *poly; /* Triangles */ X} object; X X/* Six equidistant points lying on the unit sphere */ X#define XPLUS { 1, 0, 0 } /* X */ X#define XMIN { -1, 0, 0 } /* -X */ X#define YPLUS { 0, 1, 0 } /* Y */ X#define YMIN { 0, -1, 0 } /* -Y */ X#define ZPLUS { 0, 0, 1 } /* Z */ X#define ZMIN { 0, 0, -1 } /* -Z */ X X/* Vertices of a unit octahedron */ Xtriangle octahedron[] = { X { { XPLUS, ZPLUS, YPLUS }, 0.0 }, X { { YPLUS, ZPLUS, XMIN }, 0.0 }, X { { XMIN , ZPLUS, YMIN }, 0.0 }, X { { YMIN , ZPLUS, XPLUS }, 0.0 }, X { { XPLUS, YPLUS, ZMIN }, 0.0 }, X { { YPLUS, XMIN , ZMIN }, 0.0 }, X { { XMIN , YMIN , ZMIN }, 0.0 }, X { { YMIN , XPLUS, ZMIN }, 0.0 } X}; X X/* A unit octahedron */ Xobject oct = { X sizeof(octahedron) / sizeof(octahedron[0]), X &octahedron[0] X}; X X/* Forward declarations */ Xpoint *normalize(/* point *p */); Xpoint *midpoint(/* point *a, point *b */); Xvoid print_object(/* object *obj, int level */); Xvoid print_triangle(/* triangle *t */); X X/*extern char *malloc(/* unsigned );*/ X XObject XGLSphereObjectDefine(maxlevel) Xint maxlevel; X{ X object *old, X *new; X int ccwflag = 1, /* Reverse vertex order if true */ X i, level; X Object sph; X X makeobj(sph = genobj()); X X if (ccwflag) { X /* Reverse order of points in each triangle */ X for (i = 0; i < oct.npoly; i++) { X point tmp; X tmp = oct.poly[i].pt[0]; X oct.poly[i].pt[0] = oct.poly[i].pt[2]; X oct.poly[i].pt[2] = tmp; X } X } X X old = &oct; X X /* Subdivide each starting triangle (maxlevel - 1) times */ X for (level = 1; level < maxlevel; level++) { X /* Allocate a new object */ X new = (object *)malloc(sizeof(object)); X if (new == NULL) { X fprintf(stderr, "GLSphereObjectDefine: out of memory, level %d\n", X level); X exit(1); X } X new->npoly = old->npoly * 4; X X /* Allocate 4* the number of points in the current approximation */ X new->poly = (triangle *)malloc(new->npoly * sizeof(triangle)); X if (new->poly == NULL) { X fprintf(stderr, "GLSphereObjectDefine: out of memory, level %d\n", X level); X exit(1); X } X X /* Subdivide each triangle in the old approximation and normalize X * the new points thus generated to lie on the surface of the unit X * sphere. X * Each input triangle with vertices labelled [0,1,2] as shown X * below will be turned into four new triangles: X * X * Make new points X * a = (0+2)/2 X * b = (0+1)/2 X * c = (1+2)/2 X * 1 X * /\ Normalize a, b, c X * / \ X * b/____\ c Construct new triangles X * /\ /\ [0,b,a] X * / \ / \ [b,1,c] X * /____\/____\ [a,b,c] X * 0 a 2 [a,c,2] X */ X for (i = 0; i < old->npoly; i++) { X triangle X *oldt = &old->poly[i], X *newt = &new->poly[i*4]; X point a, b, c; X X a = *normalize(midpoint(&oldt->pt[0], &oldt->pt[2])); X b = *normalize(midpoint(&oldt->pt[0], &oldt->pt[1])); X c = *normalize(midpoint(&oldt->pt[1], &oldt->pt[2])); X X newt->pt[0] = oldt->pt[0]; X newt->pt[1] = b; X newt->pt[2] = a; X newt++; X X newt->pt[0] = b; X newt->pt[1] = oldt->pt[1]; X newt->pt[2] = c; X newt++; X X newt->pt[0] = a; X newt->pt[1] = b; X newt->pt[2] = c; X newt++; X X newt->pt[0] = a; X newt->pt[1] = c; X newt->pt[2] = oldt->pt[2]; X } X X if (level > 1) { X free(old->poly); X free(old); X } X X /* Continue subdividing new triangles */ X old = new; X } X X /* Print out resulting approximation */ X X print_object(old, maxlevel); X closeobj(); X return sph; X} X X/* Normalize a point p */ Xpoint *normalize(p) Xpoint *p; X{ X static point r; X double mag; X X r = *p; X mag = r.x * r.x + r.y * r.y + r.z * r.z; X if (mag != 0.0) { X mag = 1.0 / sqrt(mag); X r.x *= mag; X r.y *= mag; X r.z *= mag; X } X X return &r; X} X X/* Return the midpoint on the line between two points */ Xpoint *midpoint(a, b) Xpoint *a, *b; X{ X static point r; X X r.x = (a->x + b->x) * 0.5; X r.y = (a->y + b->y) * 0.5; X r.z = (a->z + b->z) * 0.5; X X return &r; X} X X/* Write out all triangles in an object */ Xvoid print_object(obj, level) Xobject *obj; Xint level; X{ X int i; X X /* Spit out coordinates for each triangle */ X for (i = 0; i < obj->npoly; i++) X print_triangle(&obj->poly[i]); X} X X/* Output a triangle */ Xvoid print_triangle(t) Xtriangle *t; X{ X int i; X float p[3]; X X#ifdef sgi X bgnpolygon(); X#endif X X p[0] = t->pt[0].x; p[1] = t->pt[0].y; p[2] = t->pt[0].z; X n3f(p); X#ifdef sgi X v3f(p); X#else X pmv(p[0], p[1], p[2]); X#endif X p[0] = t->pt[1].x; p[1] = t->pt[1].y; p[2] = t->pt[1].z; X n3f(p); X#ifdef sgi X v3f(p); X#else X pdr(p[0], p[1], p[2]); X#endif X p[0] = t->pt[2].x; p[1] = t->pt[2].y; p[2] = t->pt[2].z; X n3f(p); X#ifdef sgi X v3f(p); X endpolygon(); X#else X pdr(p[0], p[1], p[2]); X pclos(); X#endif X} X X#endif END_OF_FILE if test 7060 -ne `wc -c <'rayview/spheregen.c'`; then echo shar: \"'rayview/spheregen.c'\" unpacked with wrong size! fi # end of 'rayview/spheregen.c' fi echo shar: End of archive 11 \(of 19\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 19 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0