[comp.sources.bugs] Official patch #4 for rayshade v3.0; please apply

craig@weedeater.math.yale.edu (Craig Kolb) (03/15/90)

System: rayshade version 3.0
Patch #: 4
Priority: LOW 
Subject: Patch #4

Description:

	Was possible for heightfield code to dump core.

	Appending to "mtv" format images didn't work.

	Was possible for makcone() and makcyl() to attempt rotation about
	a degenerate axis.

	Documentation was wrong and/or incomplete in a number of places.

	Pointers to colormaps were not initialized to NULL.

	Directions for compiling with -DNORLE weren't blatant enough.

	Added new gloss texture.

	The number of primitives in each object is reported in verbose mode.

	Attempting to render an empty scene now results in an error message.

	Typos in Linda-related code.

	Formatting problems with texture mapping tutorial.

	Linda code assumed shared memory.

Fix:    From rn, say "| patch -p -N -d DIR", where DIR is your rayshade source
        directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
        If you don't have the patch program, apply the following by hand,
        or get patch (version 2.0, latest patchlevel).

        After patching:
                make depend
                make

        If patch indicates that patchlevel is the wrong version, you may need
        to apply one or more previous patches, or the patch may already
        have been applied.  See the patchlevel.h file to find out what has or
        has not been applied.  In any event, don't continue with the patch.

	Previous patches and other rayshade-related materials are available via
	anonymous ftp from weedeater.math.yale.edu (130.132.23.17).

Index: src/patchlevel.h
Prereq: 3
1c1
< #define PATCHLEVEL 3
--- 1,1 ----
> #define PATCHLEVEL 4

Index: Changes
*** Changes.old	Wed Mar  7 22:16:45 1990
--- Changes	Wed Mar  7 22:16:45 1990
***************
*** 1,7 ****
--- 1,26 ----
+ Patch #4:
+ ---------
+ Added gloss texture.
+ The number of primitives in each object is reported in verbose mode.
+ Attempting to render an empty scene now results in an error message.
+ Fixed a number of typos in the documentation.
+ Fixed core-dumping bug in heightfield code.
+ Changes to makcyl() and makcone() to avoid rotating about degenerate axes.
+ Fixed thresholding bug in fBm texture.
+ Fixed bug with appending to "mtv" image files.
+ Fixed bug with the initialization of pointers to colormaps.
+ Updated Makefile.
+ Added SHAREDMEM compile-time switch for linda on shared memory machines.
+ Fixed a number of linda-related typos.
+ Fixed minor formatting problems in texture mapping tutorial.
+ 
  Patch #2/3:
  -----------
  
  Added depth of field code, courtesy of Rodney G. Bogart.
+ Removed handling of #include directives in input files.
+ Added handling of cpp-generated lines of the form '#n "filename"'.
+ Added new error and warning message routines.
  Added -F option to allow selection of frequency of status reports.
  Added reporting of total and split CPU times during verbose status reports.
  Removed hard-coded constants in several of the textures.

Index: src/Makefile
*** src/Makefile.old	Wed Mar  7 22:17:13 1990
--- src/Makefile	Wed Mar  7 22:17:13 1990
***************
*** 3,16 ****
  #
  # Craig Kolb
  #
! # $Id: Makefile,v 3.0 89/10/27 02:05:45 craig Exp $
  #
! # $Log:	Makefile,v $
! # Revision 3.0  89/10/27  02:05:45  craig
! # Baseline for first official release.
! # 
! # Location of Utah-raster library and include files, if appropriate.
! # If you are compiling with -DNORLE, leave these two undefined.
  #
  RLELIB = /usr/u/utah/lib/librle.a
  RLEINC = /usr/u/utah/include
--- 3,16 ----
  #
  # Craig Kolb
  #
! # $Id: Makefile,v 3.0.1.1 90/03/07 21:38:06 craig Exp $
  #
! # If you are using the Utah Raster Toolkit, you must set RLELIB and RLEINC
! # to be the name of the Utah Raster library and include file directory.
! #
! # If you are not using the Utah Raster Toolkit, you must compile using
! # -DNORLE (see below). In this case, you should comment out the next two
! # definitions.
  #
  RLELIB = /usr/u/utah/lib/librle.a
  RLEINC = /usr/u/utah/include
***************
*** 19,41 ****
  #
  #LCC = /homes/systems/carriero/linda/v2.2/bin/clc
  #
! # Temporary file directory, bin direction, and executable name.
  #
- TMPDIR = /tmp
  BINDIR = /usr/u/craig/bin
  SHADENAME = rayshade
  #
  # Compiler flags.
  #
! # GENERIC (BSD):	CFLAGS = -I$(RLEINC) -DTMPDIR=\"$(TMPDIR)\"
  # SYSV:			add -DSYSV
  #
  # Multimax (shared memory):
! #			add -DMULTIMAX
  # Linda:		add -DLINDA (and move raytrace.c to raytrace.cl)
  #
  # Long ago, rayshade was compiled on the Amiga using Aztec C and:
! #			CFLAGS = +fi +C +D +L -DTMPDIR="t:" -DAZTEC
  # 
  # If you are not using the Utah Raster toolkit, add -DNORLE
  # If your compiler doesn't understand the void type, add -DNOVOID
--- 19,40 ----
  #
  #LCC = /homes/systems/carriero/linda/v2.2/bin/clc
  #
! # Bin directory and executable name.
  #
  BINDIR = /usr/u/craig/bin
  SHADENAME = rayshade
  #
  # Compiler flags.
  #
! # GENERIC (BSD):	CFLAGS = -I$(RLEINC)
  # SYSV:			add -DSYSV
  #
  # Multimax (shared memory):
! #			add -DMULTIMAX -DSHAREDMEM
  # Linda:		add -DLINDA (and move raytrace.c to raytrace.cl)
  #
  # Long ago, rayshade was compiled on the Amiga using Aztec C and:
! #			CFLAGS = +fi +C +D +L -DAZTEC
  # 
  # If you are not using the Utah Raster toolkit, add -DNORLE
  # If your compiler doesn't understand the void type, add -DNOVOID
***************
*** 45,51 ****
  #
  # Be sure to add any necessary floating-point hardware switches.
  # 
! CFLAGS = -I$(RLEINC) -DTMPDIR=\"$(TMPDIR)\" -O -DSYSV
  #
  # Libraries:
  # BSD:		LIBS = $(RLELIB) -lm
--- 44,50 ----
  #
  # Be sure to add any necessary floating-point hardware switches.
  # 
! CFLAGS = -I$(RLEINC) -O -DSYSV
  #
  # Libraries:
  # BSD:		LIBS = $(RLELIB) -lm
***************
*** 149,158 ****
  setup.o: primobj.h
  setup.o: funcdefs.h
  input.o: input.c
- input.o: constants.h
- input.o: typedefs.h
- input.o: datatypes.h
- input.o: primobj.h
  input_yacc.o: input_yacc.c
  input_yacc.o: constants.h
  input_yacc.o: typedefs.h
--- 148,153 ----
***************
*** 160,165 ****
--- 155,161 ----
  input_yacc.o: primobj.h
  input_yacc.o: funcdefs.h
  input_yacc.o: texture.h
+ input_yacc.o: atmosphere.h
  input_lex.o: input_lex.c
  input_lex.o: typedefs.h
  input_lex.o: datatypes.h
***************
*** 306,311 ****
--- 302,308 ----
  shade.o: datatypes.h
  shade.o: primobj.h
  shade.o: funcdefs.h
+ shade.o: atmosphere.h
  atmosphere.o: atmosphere.c
  atmosphere.o: typedefs.h
  atmosphere.o: datatypes.h
***************
*** 312,317 ****
--- 309,315 ----
  atmosphere.o: primobj.h
  atmosphere.o: constants.h
  atmosphere.o: funcdefs.h
+ atmosphere.o: atmosphere.h
  light.o: light.c
  light.o: typedefs.h
  light.o: datatypes.h

Index: src/cone.c
*** src/cone.c.old	Wed Mar  7 22:17:21 1990
--- src/cone.c	Wed Mar  7 22:17:21 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: cone.c,v 3.0.1.2 89/12/06 16:33:44 craig Exp $
   *
   * $Log:	cone.c,v $
   * Revision 3.0.1.2  89/12/06  16:33:44  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: cone.c,v 3.0.1.3 90/02/12 13:20:58 craig Exp $
   *
   * $Log:	cone.c,v $
+  * Revision 3.0.1.3  90/02/12  13:20:58  craig
+  * patch4: Changes to avoid rotation about null axis.
+  * 
   * Revision 3.0.1.2  89/12/06  16:33:44  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 128,136 ****
  	/*
  	 * Calculate rotation matrix to map from world space to cone space.
  	 */
! 	tmp.x = axis.y;
! 	tmp.y = -axis.x;
! 	tmp.z = 0.;
  	RS_rotate(trans, &tmp, acos(axis.z));
  	RS_translate(trans, &base);
  	cone->tantheta *= cone->tantheta;
--- 131,144 ----
  	/*
  	 * Calculate rotation matrix to map from world space to cone space.
  	 */
! 	if (abs(axis.z) == 1.) {
! 		tmp.x = 1;
! 		tmp.y = tmp.z = 0.;
! 	} else {
! 		tmp.x = axis.y;
! 		tmp.y = -axis.x;
! 		tmp.z = 0.;
! 	}
  	RS_rotate(trans, &tmp, acos(axis.z));
  	RS_translate(trans, &base);
  	cone->tantheta *= cone->tantheta;

Index: src/grid.c
*** src/grid.c.old	Wed Mar  7 22:17:34 1990
--- src/grid.c	Wed Mar  7 22:17:34 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: grid.c,v 3.0 89/10/27 02:05:50 craig Exp $
   *
   * $Log:	grid.c,v $
   * Revision 3.0  89/10/27  02:05:50  craig
   * Baseline for first official release.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: grid.c,v 3.0.1.1 90/02/12 13:16:36 craig Exp $
   *
   * $Log:	grid.c,v $
+  * Revision 3.0.1.1  90/02/12  13:16:36  craig
+  * patch4: Changed obj->counter to pointer when SHAREDMEM is defined.
+  * 
   * Revision 3.0  89/10/27  02:05:50  craig
   * Baseline for first official release.
   * 
***************
*** 329,335 ****
  		 * bounding box of the ray's extent in the voxel does
  		 * not intersect the bounding box of the object, don't bother.
  		 */
! #ifdef LINDA
  		if (*obj->counter >= counter ||
  #else
  		if (obj->counter >= counter ||
--- 332,338 ----
  		 * bounding box of the ray's extent in the voxel does
  		 * not intersect the bounding box of the object, don't bother.
  		 */
! #ifdef SHAREDMEM
  		if (*obj->counter >= counter ||
  #else
  		if (obj->counter >= counter ||
***************
*** 341,347 ****
  		    obj->bounds[LOW][Z] > hz ||
  		    obj->bounds[HIGH][Z] < lz)
  			continue;
! #ifdef LINDA
  		*obj->counter = counter;
  #else
  		obj->counter = counter;
--- 344,350 ----
  		    obj->bounds[LOW][Z] > hz ||
  		    obj->bounds[HIGH][Z] < lz)
  			continue;
! #ifdef SHAREDMEM
  		*obj->counter = counter;
  #else
  		obj->counter = counter;

Index: src/hf.c
*** src/hf.c.old	Wed Mar  7 22:17:37 1990
--- src/hf.c	Wed Mar  7 22:17:38 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: hf.c,v 3.0.1.2 89/12/06 16:33:23 craig Exp $
   *
   * $Log:	hf.c,v $
   * Revision 3.0.1.2  89/12/06  16:33:23  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: hf.c,v 3.0.1.3 90/02/12 13:30:14 craig Exp $
   *
   * $Log:	hf.c,v $
+  * Revision 3.0.1.3  90/02/12  13:30:14  craig
+  * patch4: Fixed bug involving computation of hf->lsize[i]
+  * 
   * Revision 3.0.1.2  89/12/06  16:33:23  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 180,186 ****
  	for (i = 1; i < hf->levels; i++) {
  		hf->spacing[i] = hf->spacing[i-1] * hf->iBestSize;
  		hf->lsize[i] = (int)hf->spacing[i];
! 		if (hf->lsize[i-1] % hf->BestSize != 0)
  			hf->lsize[i]++;
  		hf->boundsmax[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
  		hf->boundsmin[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
--- 183,189 ----
  	for (i = 1; i < hf->levels; i++) {
  		hf->spacing[i] = hf->spacing[i-1] * hf->iBestSize;
  		hf->lsize[i] = (int)hf->spacing[i];
! 		if ((double)hf->lsize[i] != hf->spacing[i])
  			hf->lsize[i]++;
  		hf->boundsmax[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));
  		hf->boundsmin[i]=(float **)share_malloc(hf->lsize[i]*sizeof(float *));

Index: src/input_lex.l
*** src/input_lex.l.old	Wed Mar  7 22:17:43 1990
--- src/input_lex.l	Wed Mar  7 22:17:43 1990
***************
*** 13,19 ****
  /* without supplying the source, or without informing the end-user that the */
  /* source is available for no extra charge.				    */
  /*									    */
! /* $Id: input_lex.l,v 3.0.1.3 89/12/07 23:00:54 craig Exp $ */
  %{
  #include <stdio.h>
  #ifdef SYSV
--- 13,19 ----
  /* without supplying the source, or without informing the end-user that the */
  /* source is available for no extra charge.				    */
  /*									    */
! /* $Id: input_lex.l,v 3.0.1.4 90/03/07 21:26:29 craig Exp $ */
  %{
  #include <stdio.h>
  #ifdef SYSV
***************
*** 58,63 ****
--- 58,64 ----
  focaldist		{return(tFOCALDIST);}
  fog			{return(tFOG);}
  fov			{return(tFOV);}
+ gloss			{return(tGLOSS);}
  grid			{return(tGRID);}
  heightfield		{return(tHEIGHTFIELD);}
  jittered		{return(tJITTERED);}

Index: src/input_yacc.y
*** src/input_yacc.y.old	Wed Mar  7 22:17:48 1990
--- src/input_yacc.y	Wed Mar  7 22:17:48 1990
***************
*** 17,23 ****
  /* name of the person performing the modification, the date of modification,*/
  /* and the reason for such modification.				    */
  /*									    */
! /* $Id: input_yacc.y,v 3.0.1.6 89/12/07 22:55:53 craig Exp $ */
  %{
  #include <stdio.h>
  #include "constants.h"
--- 17,23 ----
  /* name of the person performing the modification, the date of modification,*/
  /* and the reason for such modification.				    */
  /*									    */
! /* $Id: input_yacc.y,v 3.0.1.8 90/03/07 21:26:42 craig Exp $ */
  %{
  #include <stdio.h>
  #include "constants.h"
***************
*** 63,69 ****
  %token <c> tSTRING
  %token tADAPTIVE tAPERTURE 
  %token tBACKGROUND tBLOTCH tBOX tBUMP tCONE tCYL tDIRECTIONAL
! %token tENDDEF tEXTENDED tEYEP tFBM tFBMBUMP tFOCALDIST tFOG tFOV tGRID
  %token tHEIGHTFIELD tJITTERED tLIGHT tLIST tLOOKP tMARBLE tMAXDEPTH tMIST
  %token tOBJECT tOUTFILE
  %token tPLANE tPOINT tPOLY tROTATE tSAMPLES
--- 63,69 ----
  %token <c> tSTRING
  %token tADAPTIVE tAPERTURE 
  %token tBACKGROUND tBLOTCH tBOX tBUMP tCONE tCYL tDIRECTIONAL
! %token tENDDEF tEXTENDED tEYEP tFBM tFBMBUMP tFOCALDIST tFOG tFOV tGLOSS tGRID
  %token tHEIGHTFIELD tJITTERED tLIGHT tLIST tLOOKP tMARBLE tMAXDEPTH tMIST
  %token tOBJECT tOUTFILE
  %token tPLANE tPOINT tPOLY tROTATE tSAMPLES
***************
*** 130,138 ****
  		;
  Primitive	: Prim Textures
  		{
! 			if (LastObj)
  				/* User may have botched prim. def. */
  				LastObj->texture = CurText;
  			CurText = (Texture *)0;
  			LastObj = (Object *)0;
  		}
--- 130,143 ----
  		;
  Primitive	: Prim Textures
  		{
! 			if (LastObj) {
  				/* User may have botched prim. def. */
  				LastObj->texture = CurText;
+ 				if (CurObj->data)
+ 					CurObj->data->prims++;
+ 				else
+ 					World->prims++;
+ 			}
  			CurText = (Texture *)0;
  			LastObj = (Object *)0;
  		}
***************
*** 324,329 ****
--- 329,338 ----
  		| tWOOD
  		{
  			$$ = NewWoodText();
+ 		}
+ 		| tGLOSS Fnumber
+ 		{
+ 			$$ = NewGlossText($2);
  		}
  		;
  Child		: Childdef Textures

Index: src/light.c
*** src/light.c.old	Wed Mar  7 22:17:52 1990
--- src/light.c	Wed Mar  7 22:17:52 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: light.c,v 3.0 89/10/27 16:17:22 craig Exp $
   *
   * $Log:	light.c,v $
   * Revision 3.0  89/10/27  16:17:22  craig
   * Baseline for first official release.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: light.c,v 3.0.1.1 90/03/07 21:28:21 craig Exp $
   *
   * $Log:	light.c,v $
+  * Revision 3.0.1.1  90/03/07  21:28:21  craig
+  * patch4: Removed LightCoordSys().
+  * 
   * Revision 3.0  89/10/27  16:17:22  craig
   * Baseline for first official release.
   * 
***************
*** 58,98 ****
  		 */
  		vecsub(lp->pos, *objpos, lray);
  		lightdist = normalize(lray);
- 	}
- }
- 
- /*
-  * Find a coordinate system perpendicular to the ray from
-  * a point of intersection to the center of an extended light source.
-  */
- LightCoordSys(lp, pos, vector, xaxis, yaxis)
- Light *lp;
- Vector *pos, *vector, *xaxis, *yaxis;
- {
- 	/*
- 	 * Vector should *not* be normalized, xaxis & yaxis should be.
- 	 */
- 	vector->x = lp->pos.x - pos->x;
- 	vector->y = lp->pos.y - pos->y;
- 	vector->z = lp->pos.z - pos->z;
- 	xaxis->x = vector->y;
- 	xaxis->y = -vector->x;
- 	xaxis->z = 0.;
- 	if (normalize(xaxis) == 0.) {
- 		xaxis->x = 0.;
- 		xaxis->y = -vector->z;
- 		xaxis->z = vector->y;
- 		if (normalize(xaxis) == 0.)
- 			fprintf(stderr,"LightCoordSys: Can't find X axis!\n");
- 		yaxis->x = (vector->y * vector->y) + (vector->z * vector->z);
- 		yaxis->y = -vector->x * vector->y;
- 		yaxis->z = -vector->x * vector->z;
- 		(void)normalize(yaxis);
- 	} else {
- 		yaxis->x = vector->x * vector->z;
- 		yaxis->y = vector->y * vector->z;
- 		yaxis->z = -(vector->x * vector->x) -(vector->y * vector->y);
- 		(void)normalize(yaxis);
  	}
  }
  
--- 61,66 ----

Index: src/main.c
*** src/main.c.old	Wed Mar  7 22:17:57 1990
--- src/main.c	Wed Mar  7 22:17:58 1990
***************
*** 1,5 ****
  char rcsid[] =
! 	"$Id: main.c,v 3.0.1.2 89/12/07 22:54:39 craig Exp $";
  /*
   * main.c
   *
--- 1,5 ----
  char rcsid[] =
! 	"$Id: main.c,v 3.0.1.3 90/03/07 21:33:09 craig Exp $";
  /*
   * main.c
   *
***************
*** 21,26 ****
--- 21,30 ----
   * and the reason for such modification.
   *
   * $Log:	main.c,v $
+  * Revision 3.0.1.3  90/03/07  21:33:09  craig
+  * patch4: Return value of times() is now checked.
+  * patch4: Workers is externed iff LINDA is defined.
+  * 
   * Revision 3.0.1.2  89/12/07  22:54:39  craig
   * patch2: Renamed utime and stime to avoid name clashes.
   * 
***************
*** 70,77 ****
  char **argv;
  {
  	unsigned long TotalRays;
! 	extern int Verbose, Cache, Workers, Jittered;
  	extern unsigned long CacheWorked, CacheFailed, ShadowHits;
  
  	/*
   	 * Initialize variables, etc.
--- 74,84 ----
  char **argv;
  {
  	unsigned long TotalRays;
! 	extern int Verbose, Cache, Jittered;
  	extern unsigned long CacheWorked, CacheFailed, ShadowHits;
+ #ifdef LINDA
+ 	extern int Workers;
+ #endif
  
  	/*
   	 * Initialize variables, etc.
***************
*** 174,180 ****
  	struct tms time;
  	long times();
  
! 	(void)times(&time);
  	*usertime = (double)time.tms_utime / (double)HZ;
  	*systime = (double)time.tms_stime / (double)HZ;
  }
--- 181,188 ----
  	struct tms time;
  	long times();
  
! 	if (times(&time) < 0)
! 		RSwarning("Cannot get cpu time?!\n");
  	*usertime = (double)time.tms_utime / (double)HZ;
  	*systime = (double)time.tms_stime / (double)HZ;
  }

Index: src/object.c
*** src/object.c.old	Wed Mar  7 22:18:08 1990
--- src/object.c	Wed Mar  7 22:18:08 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: object.c,v 3.0.1.1 89/12/06 16:33:20 craig Exp $
   *
   * $Log:	object.c,v $
   * Revision 3.0.1.1  89/12/06  16:33:20  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: object.c,v 3.0.1.2 90/02/12 13:18:44 craig Exp $
   *
   * $Log:	object.c,v $
+  * Revision 3.0.1.2  90/02/12  13:18:44  craig
+  * patch4: Changes to record number of primitives in each object.
+  * 
   * Revision 3.0.1.1  89/12/06  16:33:20  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 55,61 ****
  	new->type = type;
  	new->data = data;
  	new->trans = trans;
! #ifdef LINDA
  	/*
  	 * If the counter is in shared memory, processes will
  	 * be modifying it left-and-right.  So, we cheat and
--- 58,65 ----
  	new->type = type;
  	new->data = data;
  	new->trans = trans;
! 	new->prims = 0;
! #ifdef SHAREDMEM
  	/*
  	 * If the counter is in shared memory, processes will
  	 * be modifying it left-and-right.  So, we cheat and
***************
*** 141,149 ****
--- 145,155 ----
  	if (parent == (Object *)0) {
  		newnode->next = (ObjList *)World->data;
  		World->data = (char *)newnode;
+ 		World->prims += child->prims;
  	} else {
  		newnode->next = (ObjList *)parent->data;
  		parent->data = (char *)newnode;
+ 		parent->prims += child->prims;
  	}
  	return newobj;
  }
***************
*** 182,187 ****
--- 188,195 ----
  		 */
  		fprintf(fstats,"Object \"%s\" extent:\n", obj->name);
  		print_bounds(obj->bounds);
+ 		fprintf(fstats,"\t%ld primitive%c\n",obj->prims,
+ 				obj->prims == 1 ? ' ' : 's');
  	}
  }
  

Index: src/outputp.c
*** src/outputp.c.old	Wed Mar  7 22:18:11 1990
--- src/outputp.c	Wed Mar  7 22:18:12 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: outputp.c,v 3.0.1.1 89/12/06 16:33:17 craig Exp $
   *
   * $Log:	outputp.c,v $
   * Revision 3.0.1.1  89/12/06  16:33:17  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: outputp.c,v 3.0.1.2 90/02/12 16:09:05 craig Exp $
   *
   * $Log:	outputp.c,v $
+  * Revision 3.0.1.2  90/02/12  16:09:05  craig
+  * patch4: Fixed bug with duplicate headers in mtv files when Appending.
+  * 
   * Revision 3.0.1.1  89/12/06  16:33:17  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 150,156 ****
  	} else
  		imgfile = stdout;
  
! 	fprintf(imgfile,"%d %d\n",Xres, Yres);
  	fflush(imgfile);
  }
  
--- 153,161 ----
  	} else
  		imgfile = stdout;
  
! 	if (!Appending)
! 		fprintf(imgfile,"%d %d\n",Xres, Yres);
! 
  	fflush(imgfile);
  }
  

Index: src/ray_options.c
*** src/ray_options.c.old	Wed Mar  7 22:18:20 1990
--- src/ray_options.c	Wed Mar  7 22:18:21 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: ray_options.c,v 3.0.1.4 89/12/06 16:33:55 craig Exp $
   *
   * $Log:	ray_options.c,v $
   * Revision 3.0.1.4  89/12/06  16:33:55  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: ray_options.c,v 3.0.1.5 90/02/12 13:28:19 craig Exp $
   *
   * $Log:	ray_options.c,v $
+  * Revision 3.0.1.5  90/02/12  13:28:19  craig
+  * patch4: Fixed typo in 'W' option error message.
+  * 
   * Revision 3.0.1.4  89/12/06  16:33:55  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 190,196 ****
  			case 'W':
  				Workers = atoi(argv[1]);
  				if (Workers < 0 || Workers > 17) {
! 					RSerror("%d workers?\n",workers);
  				}
  				argv++; argc--;
  				break;
--- 193,199 ----
  			case 'W':
  				Workers = atoi(argv[1]);
  				if (Workers < 0 || Workers > 17) {
! 					RSerror("%d workers?\n",Workers);
  				}
  				argv++; argc--;
  				break;

Index: src/raymath.c
*** src/raymath.c.old	Wed Mar  7 22:18:22 1990
--- src/raymath.c	Wed Mar  7 22:18:23 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: raymath.c,v 3.0 89/10/27 02:06:01 craig Exp $
   *
   * $Log:	raymath.c,v $
   * Revision 3.0  89/10/27  02:06:01  craig
   * Baseline for first official release.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: raymath.c,v 3.0.1.1 90/03/07 21:26:08 craig Exp $
   *
   * $Log:	raymath.c,v $
+  * Revision 3.0.1.1  90/03/07  21:26:08  craig
+  * patch4: Added VectCoordSys().
+  * 
   * Revision 3.0  89/10/27  02:06:01  craig
   * Baseline for first official release.
   * 
***************
*** 99,104 ****
--- 102,136 ----
  	k = kn * cos1 - sqrt(cos2);
  	veccomb(kn, I, k, N, dir);
  	return FALSE;
+ }
+ 
+ /*
+  * Given a vector, find two additional vectors such that all three
+  * are mutually perpendicular and xaxis X yaxis = vector.  The given
+  * vector need not be normalized. xaxis and yaxis are normalized.
+  */
+ VectCoordSys(vector, xaxis, yaxis)
+ Vector *vector, *xaxis, *yaxis;
+ {
+ 	xaxis->x = vector->y;
+ 	xaxis->y = -vector->x;
+ 	xaxis->z = 0.;
+ 	if (normalize(xaxis) == 0.) {
+ 		xaxis->x = 0.;
+ 		xaxis->y = -vector->z;
+ 		xaxis->z = vector->y;
+ 		if (normalize(xaxis) == 0.)
+ 			RSwarning("LightCoordSys: Can't find X axis!\n");
+ 		yaxis->x = (vector->y * vector->y) + (vector->z * vector->z);
+ 		yaxis->y = -vector->x * vector->y;
+ 		yaxis->z = -vector->x * vector->z;
+ 		(void)normalize(yaxis);
+ 	} else {
+ 		yaxis->x = vector->x * vector->z;
+ 		yaxis->y = vector->y * vector->z;
+ 		yaxis->z = -(vector->x * vector->x) -(vector->y * vector->y);
+ 		(void)normalize(yaxis);
+ 	}
  }
  
  #ifdef DUMB_CPP

Index: src/raytrace.c
*** src/raytrace.c.old	Wed Mar  7 22:18:27 1990
--- src/raytrace.c	Wed Mar  7 22:18:28 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: raytrace.c,v 3.0.1.5 89/12/07 22:55:25 craig Exp $
   *
   * $Log:	raytrace.c,v $
   * Revision 3.0.1.5  89/12/07  22:55:25  craig
   * patch2: Renamed utime and stime to avoid name clashes.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: raytrace.c,v 3.0.1.6 90/02/12 13:29:09 craig Exp $
   *
   * $Log:	raytrace.c,v $
+  * Revision 3.0.1.6  90/02/12  13:29:09  craig
+  * patch4: Changes to reflect new variable names in linda code.
+  * 
   * Revision 3.0.1.5  89/12/07  22:55:25  craig
   * patch2: Renamed utime and stime to avoid name clashes.
   * 
***************
*** 102,108 ****
  {
  #ifdef LINDA
  	extern unsigned long primtests[], primhits[];
! 	extern double usertime, systime;
  	extern unsigned long EyeRays, ShadowRays, ReflectRays, RefractRays,
  			CacheWorked, CacheFailed, ShadowHits, SuperSampled,
  			BVTests, HitRays;
--- 105,111 ----
  {
  #ifdef LINDA
  	extern unsigned long primtests[], primhits[];
! 	extern double Utime, Stime;
  	extern unsigned long EyeRays, ShadowRays, ReflectRays, RefractRays,
  			CacheWorked, CacheFailed, ShadowHits, SuperSampled,
  			BVTests, HitRays;
***************
*** 153,160 ****
  			primhits[j] += hittmp[j];
  		}
  		in ("timing", ? utmp, ? stmp);
! 		usertime += utmp / (double)Workers;
! 		systime += stmp / (double)Workers;
  		in("worker", ? int);
  	}
  #endif
--- 156,163 ----
  			primhits[j] += hittmp[j];
  		}
  		in ("timing", ? utmp, ? stmp);
! 		Utime += utmp / (double)Workers;
! 		Stime += stmp / (double)Workers;
  		in("worker", ? int);
  	}
  #endif

Index: src/setup.c
*** src/setup.c.old	Wed Mar  7 22:18:31 1990
--- src/setup.c	Wed Mar  7 22:18:31 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: setup.c,v 3.0.1.1 89/12/02 16:52:33 craig Exp $
   *
   * $Log:	setup.c,v $
   * Revision 3.0.1.1  89/12/02  16:52:33  craig
   * patch2: Added code to set default value for ReportFreq.
   * 
--- 18,30 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: setup.c,v 3.0.1.2 90/02/12 13:26:49 craig Exp $
   *
   * $Log:	setup.c,v $
+  * Revision 3.0.1.2  90/02/12  13:26:49  craig
+  * patch4: Added calls to new error/warning routines.
+  * patch4: Attempting to render empty scene now results in an error message.
+  * 
   * Revision 3.0.1.1  89/12/02  16:52:33  craig
   * patch2: Added code to set default value for ReportFreq.
   * 
***************
*** 56,63 ****
  	 */
  	bytes = 1 << SHARED_BYTES;
  	if (share_malloc_init(bytes) == -1) {
! 		fprintf(stderr,"Cannot share_malloc %d bytes.\n",bytes);
! 		exit(10);
  	} else
  		fprintf(stderr,"Malloced %d bytes of shared memory.\n",
  				bytes);
--- 60,66 ----
  	 */
  	bytes = 1 << SHARED_BYTES;
  	if (share_malloc_init(bytes) == -1) {
! 		RSerror("Cannot share_malloc %d bytes.\n",bytes);
  	} else
  		fprintf(stderr,"Malloced %d bytes of shared memory.\n",
  				bytes);
***************
*** 102,107 ****
--- 105,111 ----
  cleanup()
  {
  	int i;
+ 	extern Object *World;
  	extern int nlight, maxlevel;
  	extern int Xres, Yres, StartLine, Jittered, JitSamples, pixel_div;
  	extern double RedContrast, GreenContrast, BlueContrast, TreeCutoff;
***************
*** 110,115 ****
--- 114,125 ----
  	extern FILE *fstats;
  
  	/*
+ 	 * Complain if there are no primitives to be rendered.
+ 	 */
+ 	if (World->prims == 0) {
+ 		RSerror("Nothing to be rendered.\n");
+ 	}
+ 	/*
  	 * Because we want the user to be able to override the input file
  	 * through the command line, we have to initialize some variables to
  	 * bogus values so that when the file is being parsed, it is
***************
*** 144,156 ****
  		JitSamples = DEFLIGHTSAMPLES;
  
  	if (Jittered && JitSamples > 5) {
! 		fprintf(stderr,"Sorry, %d rays/pixel not supported.\n",
  						JitSamples*JitSamples);
- 		exit(2);
  	}
  	if (!Jittered && JitSamples < 3) {
! 		fprintf(stderr,"Samples (-S) value must be at least 3.\n");
! 		exit(2);
  	}
  
  	if (TreeCutoff == UNSET)
--- 154,164 ----
  		JitSamples = DEFLIGHTSAMPLES;
  
  	if (Jittered && JitSamples > 5) {
! 		RSerror("Sorry, %d rays/pixel not supported.\n",
  						JitSamples*JitSamples);
  	}
  	if (!Jittered && JitSamples < 3) {
! 		RSerror("Samples (-S) value must be at least 3.\n");
  	}
  
  	if (TreeCutoff == UNSET)

Index: src/shade.c
*** src/shade.c.old	Wed Mar  7 22:18:33 1990
--- src/shade.c	Wed Mar  7 22:18:34 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: shade.c,v 3.0.1.1 89/11/16 20:34:42 craig Exp Locker: craig $
   *
   * $Log:	shade.c,v $
   * Revision 3.0.1.1  89/11/16  20:34:42  craig
   * patch1: Atmospheric effects are now applied to background rays.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: shade.c,v 3.0.1.2 90/03/07 21:31:21 craig Exp $
   *
   * $Log:	shade.c,v $
+  * Revision 3.0.1.2  90/03/07  21:31:21  craig
+  * patch4: Replaced call to LightCoordSys() with call to VectCoordSys().
+  * 
   * Revision 3.0.1.1  89/11/16  20:34:42  craig
   * patch1: Atmospheric effects are now applied to background rays.
   * 
***************
*** 229,236 ****
  	 * whose normal is defined by the vector from the center
  	 * of the light source to the point of intersection and
  	 * which passes through the center of the light source.
!  	*/
! 	LightCoordSys(lp, pos, &toLight, &Uaxis, &Vaxis);
  	jit = 2. * lp->radius * SampleSpacing;
  
  	if (Jittered) {
--- 232,241 ----
  	 * whose normal is defined by the vector from the center
  	 * of the light source to the point of intersection and
  	 * which passes through the center of the light source.
!  	 */
! 	vecsub(lp->pos, *pos, &toLight);
! 	VectCoordSys(&toLight, &Uaxis, &Vaxis);
! 
  	jit = 2. * lp->radius * SampleSpacing;
  
  	if (Jittered) {

Index: src/texture.h
*** src/texture.h.old	Wed Mar  7 22:18:47 1990
--- src/texture.h	Wed Mar  7 22:18:48 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: texture.h,v 3.0 89/10/27 02:06:06 craig Exp $
   *
   * $Log:	texture.h,v $
   * Revision 3.0  89/10/27  02:06:06  craig
   * Baseline for first official release.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: texture.h,v 3.0.1.1 90/03/07 21:27:15 craig Exp $
   *
   * $Log:	texture.h,v $
+  * Revision 3.0.1.1  90/03/07  21:27:15  craig
+  * patch4: Added support for gloss texture.
+  * 
   * Revision 3.0  89/10/27  02:06:06  craig
   * Baseline for first official release.
   * 
***************
*** 33,44 ****
  #define FBM		4	/* fBm texture */
  #define FBMBUMP		5	/* fBm bump map */
  #define WOOD		6
  
  Texture *NewCheckText(), *NewBlotchText(), *NewBumpText(), *NewMarbleText();
  Texture *NewfBmText(), *NewfBmBumpText();
! Texture *NewWoodText();
  /*
   * Texturing routines.
   */
  int	CheckerText(), BlotchText(), BumpText(), MarbleText(), fBmText();
! int	fBmBumpText(), WoodText();
--- 36,48 ----
  #define FBM		4	/* fBm texture */
  #define FBMBUMP		5	/* fBm bump map */
  #define WOOD		6
+ #define GLOSS		7
  
  Texture *NewCheckText(), *NewBlotchText(), *NewBumpText(), *NewMarbleText();
  Texture *NewfBmText(), *NewfBmBumpText();
! Texture *NewWoodText(), *NewGlossText();
  /*
   * Texturing routines.
   */
  int	CheckerText(), BlotchText(), BumpText(), MarbleText(), fBmText();
! int	fBmBumpText(), WoodText(), GlossText();

Index: doc/texture.ms
*** doc/texture.ms.old	Wed Mar  7 22:17:10 1990
--- doc/texture.ms	Wed Mar  7 22:17:10 1990
***************
*** 2,10 ****
  .\" Brief tutorial on adding textures to rayshade.
  .\" Craig Kolb 10/89
  .\"
! .\" $Id: texture.ms,v 3.0.1.1 89/11/27 18:49:26 craig Exp $
  .\"
  .\" $Log:	texture.ms,v $
  .\" Revision 3.0.1.1  89/11/27  18:49:26  craig
  .\" patch2: Example texture now uses colormap to scale ambient & diffuse
  .\" patch2: components of surface color.
--- 2,13 ----
  .\" Brief tutorial on adding textures to rayshade.
  .\" Craig Kolb 10/89
  .\"
! .\" $Id: texture.ms,v 3.0.1.2 90/02/12 12:44:41 craig Exp $
  .\"
  .\" $Log:	texture.ms,v $
+ .\" Revision 3.0.1.2  90/02/12  12:44:41  craig
+ .\" patch4: Fixed minor formatting problems.
+ .\" 
  .\" Revision 3.0.1.1  89/11/27  18:49:26  craig
  .\" patch2: Example texture now uses colormap to scale ambient & diffuse
  .\" patch2: components of surface color.
***************
*** 70,76 ****
  .LP
  Adding new textures to rayshade involves modifying at least
  four source files:
! .NH texture.h
  texture.h
  .LP
  A numerical type is given to the texture.  The routines to
--- 73,79 ----
  .LP
  Adding new textures to rayshade involves modifying at least
  four source files:
! .NH
  texture.h
  .LP
  A numerical type is given to the texture.  The routines to

Index: src/typedefs.h
*** src/typedefs.h.old	Wed Mar  7 22:18:52 1990
--- src/typedefs.h	Wed Mar  7 22:18:52 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: typedefs.h,v 3.0 89/10/27 02:06:07 craig Exp $
   *
   * $Log:	typedefs.h,v $
   * Revision 3.0  89/10/27  02:06:07  craig
   * Baseline for first official release.
   * 
--- 18,30 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: typedefs.h,v 3.0.1.1 90/02/12 13:22:35 craig Exp $
   *
   * $Log:	typedefs.h,v $
+  * Revision 3.0.1.1  90/02/12  13:22:35  craig
+  * patch4: Added prims field to Object structure.
+  * patch4: Object->counter is a pointer when SHAREDMEM is defined.
+  * 
   * Revision 3.0  89/10/27  02:06:07  craig
   * Baseline for first official release.
   * 
***************
*** 49,55 ****
  	char *data;		/* Pointer to list/grid/primitive */
  	Trans *trans;		/* Transformation information */
  	double bounds[2][3];	/* Bounding box */
! #ifdef LINDA
  	unsigned long *counter;
  #else
  	unsigned long counter;		/* # of last grid checked against */
--- 53,60 ----
  	char *data;		/* Pointer to list/grid/primitive */
  	Trans *trans;		/* Transformation information */
  	double bounds[2][3];	/* Bounding box */
! 	unsigned long prims;	/* # of primitives, including sub-objects */
! #ifdef SHAREDMEM
  	unsigned long *counter;
  #else
  	unsigned long counter;		/* # of last grid checked against */

Index: src/voxels.c
*** src/voxels.c.old	Wed Mar  7 22:18:58 1990
--- src/voxels.c	Wed Mar  7 22:18:58 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: voxels.c,v 3.0.1.1 89/12/06 16:33:29 craig Exp $
   *
   * $Log:	voxels.c,v $
   * Revision 3.0.1.1  89/12/06  16:33:29  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,29 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: voxels.c,v 3.0.1.2 90/02/12 13:19:50 craig Exp $
   *
   * $Log:	voxels.c,v $
+  * Revision 3.0.1.2  90/02/12  13:19:50  craig
+  * patch4: Added reporting of total number of primitives.
+  * 
   * Revision 3.0.1.1  89/12/06  16:33:29  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 51,56 ****
--- 54,61 ----
  	if (Verbose) {
  		fprintf(fstats,"World extent:\n");
  		print_bounds(World->bounds);
+ 		fprintf(fstats,"\t%ld primitive%c\n",World->prims,
+ 				World->prims == 1 ? ' ' : 's');
  	}
  }
  

Index: src/cylinder.c
*** src/cylinder.c.old	Thu Mar  8 18:41:52 1990
--- src/cylinder.c	Thu Mar  8 18:42:01 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: cylinder.c,v 3.0.1.2 89/12/06 16:33:41 craig Exp $
   *
   * $Log:	cylinder.c,v $
   * Revision 3.0.1.2  89/12/06  16:33:41  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,32 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: cylinder.c,v 3.0.1.4 90/03/07 22:43:04 craig Exp $
   *
   * $Log:	cylinder.c,v $
+  * Revision 3.0.1.4  90/03/07  22:43:04  craig
+  * patch4: Fixed typo in previous fix.
+  * 
+  * Revision 3.0.1.3  90/02/12  13:27:30  craig
+  * patch4: Changes to avoid rotation about null axis.
+  * 
   * Revision 3.0.1.2  89/12/06  16:33:41  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 79,87 ****
  	/*
  	 * Define matrix to transform from axis-aligned to desired cylinder.
  	 */
! 	dir.x = axis.y;
! 	dir.y = -axis.x;
! 	dir.z = 0.;
  	RS_rotate(trans, &dir, acos(axis.z));
  	RS_translate(trans, cent);
  
--- 85,98 ----
  	/*
  	 * Define matrix to transform from axis-aligned to desired cylinder.
  	 */
! 	if (abs(axis.z) == 1.) {
! 		dir.x = 1.;
! 		dir.y = dir.z = 0.;
! 	} else {
! 		dir.x = axis.y;
! 		dir.y = -axis.x;
! 		dir.z = 0.;
! 	}
  	RS_rotate(trans, &dir, acos(axis.z));
  	RS_translate(trans, cent);
  

Index: Examples/pool.ray
*** Examples/pool.ray.old	Thu Mar  8 18:31:24 1990
--- Examples/pool.ray	Thu Mar  8 18:31:24 1990
***************
*** 9,14 ****
--- 9,21 ----
   * To speed rendering, use -P or -S options.
   *
   * C. Kolb 2/88
+  *
+  * $Id: pool.ray,v 3.0.1.1 90/03/08 18:24:39 craig Exp $
+  *
+  * $Log:	pool.ray,v $
+  * Revision 3.0.1.1  90/03/08  18:24:39  craig
+  * patch4: Modified transformation of wood & marble textures.
+  * 
   */
  up 0.0 0.0 1.
  fov 45
***************
*** 70,79 ****
  	sphere s9 1.5 -6.0	-31.392305	1.5
  
  	box s4 0. 0. -1. 30. 57. 1.
! 	box s15 30. 0. 0. 3. 54. 1.5 texture wood scale 5. 5. 5.
! 	box s15 -30. 0. 0. 3. 54. 1.5 texture wood scale 5. 5. 5.
! 	box s15 0. 57. 0. 33. 3. 1.5 texture wood scale 5. 5. 5.
! 	box s15 0. -57. 0. 33. 3. 1.5 texture wood scale 5. 5. 5.
  	sphere s16 1.5 0. 0. 0. translate 0. 21. 1.5
  	box mirror 10. -144. 30. 21.3333 .1 20.	/* was 40. -144 30. */
  	/*
--- 77,86 ----
  	sphere s9 1.5 -6.0	-31.392305	1.5
  
  	box s4 0. 0. -1. 30. 57. 1.
! 	box s15 30. 0. 0. 3. 54. 1.5 texture wood scale 15. 10. 15.
! 	box s15 -30. 0. 0. 3. 54. 1.5 texture wood scale 15. 10. 15.
! 	box s15 0. 57. 0. 33. 3. 1.5 texture wood scale 10. 15. 15.
! 	box s15 0. -57. 0. 33. 3. 1.5 texture wood scale 10. 15. 15.
  	sphere s16 1.5 0. 0. 0. translate 0. 21. 1.5
  	box mirror 10. -144. 30. 21.3333 .1 20.	/* was 40. -144 30. */
  	/*
***************
*** 87,93 ****
  	 * Floor
  	 */
  	plane floor   0.	 0.	1.	0.	   0. -30.
! 		texture marble scale 4. 4. 4. translate 0. 0. -4.376 
  		texture checker blacktile scale 12.3 12.3 12.3
  	/*
  	 * Ceiling
--- 94,101 ----
  	 * Floor
  	 */
  	plane floor   0.	 0.	1.	0.	   0. -30.
! 		texture marble scale 6. 6. 6. rotate 1 0 0 90
! 				translate 0. 0. -4.376 
  		texture checker blacktile scale 12.3 12.3 12.3
  	/*
  	 * Ceiling

Index: doc/rayshade.1
*** doc/rayshade.1.old	Thu Mar  8 18:39:55 1990
--- doc/rayshade.1	Thu Mar  8 18:40:06 1990
***************
*** 1,8 ****
  .\" Manual page for rayshade, 'troff -man' format.
  .\"
! .\" $Id: rayshade.1,v 3.0.1.11 89/12/06 17:21:39 craig Exp $
  .\"
  .\" $Log:	rayshade.1,v $
  .\" Revision 3.0.1.11  89/12/06  17:21:39  craig
  .\" patch2: Added suggestion to use cpp.
  .\" 
--- 1,19 ----
  .\" Manual page for rayshade, 'troff -man' format.
  .\"
! .\" $Id: rayshade.1,v 3.0.1.14 90/03/08 18:20:10 craig Exp $
  .\"
  .\" $Log:	rayshade.1,v $
+ .\" Revision 3.0.1.14  90/03/08  18:20:10  craig
+ .\" patch4: More typos...
+ .\" 
+ .\" Revision 3.0.1.13  90/03/07  22:15:15  craig
+ .\" patch4: Documented gloss texture.
+ .\" patch4: Better documentation of heightfields.
+ .\" patch4: General cleanup.
+ .\" 
+ .\" Revision 3.0.1.12  90/02/12  13:10:13  craig
+ .\" patch4: Fixed errors in fbm and fbmbump documentation.
+ .\" 
  .\" Revision 3.0.1.11  89/12/06  17:21:39  craig
  .\" patch2: Added suggestion to use cpp.
  .\" 
***************
*** 129,135 ****
  .SH OVERVIEW
  .PP
  .I Rayshade
! is an ray tracer capable of rendering images composed
  of a large number of primitive objects.
  .I Rayshade
  reads a series of lines supplied on the standard input or contained
--- 140,146 ----
  .SH OVERVIEW
  .PP
  .I Rayshade
! is a ray tracing program capable of rendering images composed
  of a large number of primitive objects.
  .I Rayshade
  reads a series of lines supplied on the standard input or contained
***************
*** 280,286 ****
  .PP
  Three types of light sources are supported:  point, extended (area), and
  directional.
! Point sources are specified by a location in world-space
  and produce shadows with sharp edges.  Extended sources are specified
  by a location and a radius.  They produce shadows with "fuzzy" edges
  (penumbrae), but increase ray tracing time considerably.  Directional
--- 291,297 ----
  .PP
  Three types of light sources are supported:  point, extended (area), and
  directional.
! Point sources are specified by a location in world space
  and produce shadows with sharp edges.  Extended sources are specified
  by a location and a radius.  They produce shadows with "fuzzy" edges
  (penumbrae), but increase ray tracing time considerably.  Directional
***************
*** 327,334 ****
  .SH SURFACES
  .PP
  Every primitive object has a surface associated with it.  The surface specifies 
! the color, reflectivity, and transparency of an object, and may be
! defined anywhere in the input file as long as it is defined before it
  is used.
  Surfaces are
  defined once, and may be associated with any number of primitive objects.
--- 338,345 ----
  .SH SURFACES
  .PP
  Every primitive object has a surface associated with it.  The surface specifies 
! the color, reflectivity, and transparency of an object.  A surface may be
! defined anywhere in the input file, provided it is defined before it
  is used.
  Surfaces are
  defined once, and may be associated with any number of primitive objects.
***************
*** 470,480 ****
  Defines a Phong-shaded triangle.  Here, the first three floating-point numbers
  specify the first vertex, the second three specify the
  normal at that vertex, and so on.  Again, vertices should be
! specified in counter-clockwise order.
! Currently, all three vertex/normal pairs
! are stored for every triangle (as opposed to storing pointers to these
! vectors, which would reduce storage space in cases where more than one
! triangle shared a vertex).
  .TP
  \fBpoly \fIsurface x1 y1 z1 x2 y2 z2 x3 y3 z3 \fR[\fIx4 y4 z4 ...\fR]
  Creates a polygon with the specified vertices.  The vertices should be given in
--- 481,487 ----
  Defines a Phong-shaded triangle.  Here, the first three floating-point numbers
  specify the first vertex, the second three specify the
  normal at that vertex, and so on.  Again, vertices should be
! specified in counter-clockwise order. Vertex normals need not be normalized.
  .TP
  \fBpoly \fIsurface x1 y1 z1 x2 y2 z2 x3 y3 z3 \fR[\fIx4 y4 z4 ...\fR]
  Creates a polygon with the specified vertices.  The vertices should be given in
***************
*** 503,517 ****
  .I top_radius.
  .TP
  \fBheightfield \fIsurface filename\fR
! Reads height field data from \fIfilename\fR and creates a height square
! height field of unit size centered at (0.5, 0.5).  The binary data in
! \fIfilename\fR
! is stored as an initial integer giving the square root of number of data
! points in the file, followed by altitude (Z) values stored as floating-point
! numbers.  The height field is rendered as a surface tessellated by triangles.
! Non-square height fields may be rendered by setting vertex heights to
  less than or equal to -1000.  Triangles which have any vertex less than
! or equal in altitude to this value are not rendered.
  .TP
  \fBbox \fIsurface xcenter ycenter zcenter xsize ysize zsize\fR
  Creates a box centered at (
--- 510,532 ----
  .I top_radius.
  .TP
  \fBheightfield \fIsurface filename\fR
! Reads height field data from \fIfilename\fR and creates a square
! height field of unit size centered at (0.5, 0.5).  The height field is
! rendered as a surface tessellated by right isoscoles triangles.  The binary
! data in the heightfield file is stored as an initial
! 32-bit integer giving the square root of number of data
! points in the file, termed the size of the height field.  The size is
! followed by altitude (Z) values stored as 32-bit
! floating point values.  The 0th value in the file specifies the Z coordinate
! of the lower-left corner of the height field (0, 0).  The next 
! specifies the Z coordinate for (1/(size-1), 0).  The last specifies the
! coordinate for (1., 1.).  In short, value number \fIi\fR
! in the heightfield file specifies the Z coordinate for the point
! ( (i % size) / (size -1), (i / size) / (size -1) ).
! Non-square height fields may be rendered by specifying altitude values
  less than or equal to -1000.  Triangles which have any vertex less than
! or equal in altitude to this value are not rendered.  Be warned that the
! heightfield file is machine-dependent, as it is stored in binary format.
  .TP
  \fBbox \fIsurface xcenter ycenter zcenter xsize ysize zsize\fR
  Creates a box centered at (
***************
*** 696,712 ****
  Versions of Perlin's Noise() and DNoise()
  functions are used to generate values for
  most of the interesting textures.
! Currently, there are seven textures available:
  .TP
  \fBbump\fI scale\fR
! applies a random bump map to the surface being textured.  The point of
  intersection is passed to DNoise().  The returned normalized vector is
  weighted by
  .I scale
  and added to the normal vector at the point of intersection.
  .TP
! \fBchecker\fI size surface\fR
! applies a (3D) checkerboard texture to the object being textured.  Every
  point that falls within an "even" cube will be shaded using the characteristics
  of the named surface.  Every point that falls within an "odd" cube will
  retain its usual surface characteristics.  Be warned that strange effects
--- 711,727 ----
  Versions of Perlin's Noise() and DNoise()
  functions are used to generate values for
  most of the interesting textures.
! There are eight available textures:
  .TP
  \fBbump\fI scale\fR
! Applies a random bump map to the surface being textured.  The point of
  intersection is passed to DNoise().  The returned normalized vector is
  weighted by
  .I scale
  and added to the normal vector at the point of intersection.
  .TP
! \fBchecker\fI surface\fR
! Applies a (3D) checkerboard texture to the object being textured.  Every
  point that falls within an "even" cube will be shaded using the characteristics
  of the named surface.  Every point that falls within an "odd" cube will
  retain its usual surface characteristics.  Be warned that strange effects
***************
*** 721,727 ****
  of 0 results in a roughly 50-50 mix of the two surfaces.
  Higher values result in greater instances of the 'default' surface type.
  .TP
! \fBfbm \fIscale offset H lambda octaves thresh\fR [\fIcolormap\fR]
  This texture generates a sample of discretized fractional Brownian motion (fBm)
  and uses it to modify the diffuse and ambient components of an object's color.
  If no \fIcolormap\fR is named, the sample
--- 736,742 ----
  of 0 results in a roughly 50-50 mix of the two surfaces.
  Higher values result in greater instances of the 'default' surface type.
  .TP
! \fBfbm \fIoffset scale H lambda octaves thresh\fR [\fIcolormap\fR]
  This texture generates a sample of discretized fractional Brownian motion (fBm)
  and uses it to modify the diffuse and ambient components of an object's color.
  If no \fIcolormap\fR is named, the sample
***************
*** 741,752 ****
  works well), and \fIthresh\fR is used to specify a lower bound on the
  output of fBm function.  Any value lower than \fIthresh\fR is set to zero.
  .TP
! \fBfbmbump \fIscale offset H lambda octaves thresh\fR
  This texture is similar to the \fBfbm\fR texture.  Rather modifying the
  color of a surface, \fBfbmbump\fR acts as a bump map.
  .TP
  \fBmarble\fR [\fIcolormap\fR]
! This texture gives a surface a marble-like appearance.  If the name of a
  \fIcolormap\fR file is given, the marble will be colored using the RGB values
  in the colormap.  If no colormap name is given, the diffuse and ambient
  components of
--- 756,778 ----
  works well), and \fIthresh\fR is used to specify a lower bound on the
  output of fBm function.  Any value lower than \fIthresh\fR is set to zero.
  .TP
! \fBfbmbump \fIoffset scale H lambda octaves\fR
  This texture is similar to the \fBfbm\fR texture.  Rather modifying the
  color of a surface, \fBfbmbump\fR acts as a bump map.
  .TP
+ \fBgloss \fIglossiness\fR
+ This texture gives reflective surfaces a glossy appearance. A glossy
+ object's surface normal is perturbed such that it 'samples' a cone of
+ unit height with radius 1. - \fIglossiness\fR.  Thus, a value of 1 results
+ in perfect mirror-like reflections, while a value of 0 results in extremely
+ fuzzy reflections.  For best results, jittered sampling should be
+ used when rendering scenes containing glossy objects.
+ .TP
  \fBmarble\fR [\fIcolormap\fR]
! This texture gives a surface a marble-like appearance.  The texture
! is implemented as roughly parallel alternating veins of marble, each
! of which is separated by 1/7 of a unit and runs perpendicular to the Z axis.
! If the name of a
  \fIcolormap\fR file is given, the marble will be colored using the RGB values
  in the colormap.  If no colormap name is given, the diffuse and ambient
  components of
***************
*** 755,761 ****
  .TP
  \fBwood\fR
  .br
! This texture gives a wood-like appearance to a surface.
  .PP
  A colormap is an ASCII file
  256 lines in length, each line containing three space-separated integers
--- 781,790 ----
  .TP
  \fBwood\fR
  .br
! This texture gives a wood-like appearance to a surface.  The feature size
! of the texture is approximately 1/100th of a unit, making it often necessary
! to scale the texture in order to achieve the desired
! appearance.
  .PP
  A colormap is an ASCII file
  256 lines in length, each line containing three space-separated integers
***************
*** 868,874 ****
  skipped,  \fIsamples\fR must be at least 3 if adaptive supersampling is
  being used.
  .PP
! Not that the meaning of the \fB-S\fR option (and the \fBsamples\fR
  command) is different depending upon
  whether or not jittered
  sampling is being used.
--- 897,903 ----
  skipped,  \fIsamples\fR must be at least 3 if adaptive supersampling is
  being used.
  .PP
! Note that the meaning of the \fB-S\fR option (and the \fBsamples\fR
  command) is different depending upon
  whether or not jittered
  sampling is being used.

Index: src/texture.c
*** src/texture.c.old	Thu Mar  8 18:38:25 1990
--- src/texture.c	Thu Mar  8 18:39:00 1990
***************
*** 18,26 ****
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: texture.c,v 3.0.1.2 89/12/06 16:33:50 craig Exp $
   *
   * $Log:	texture.c,v $
   * Revision 3.0.1.2  89/12/06  16:33:50  craig
   * patch2: Added calls to new error/warning routines.
   * 
--- 18,31 ----
   * name of the person performing the modification, the date of modification,
   * and the reason for such modification.
   *
!  * $Id: texture.c,v 3.0.1.3 90/03/07 21:30:22 craig Exp $
   *
   * $Log:	texture.c,v $
+  * Revision 3.0.1.3  90/03/07  21:30:22  craig
+  * patch4: Fixed thresholding bug in fBmText().
+  * patch4: Colormap is now set to NULL in new_texture().
+  * patch4: Added gloss texture.
+  * 
   * Revision 3.0.1.2  89/12/06  16:33:50  craig
   * patch2: Added calls to new error/warning routines.
   * 
***************
*** 44,50 ****
   */
  int (*textures[])() =
  	{CheckerText, BlotchText, BumpText, MarbleText, fBmText, fBmBumpText,
! 	 WoodText};
  extern double Chaos(), Marble(), fBm(), Noise();
  Color	*read_colormap();
  
--- 49,55 ----
   */
  int (*textures[])() =
  	{CheckerText, BlotchText, BumpText, MarbleText, fBmText, fBmBumpText,
! 	 WoodText, GlossText};
  extern double Chaos(), Marble(), fBm(), Noise();
  Color	*read_colormap();
  
***************
*** 62,67 ****
--- 67,73 ----
  	new->surf1 = (Surface *)NULL;
  	new->next = (Texture *)NULL;
  	new->trans = (Trans *)NULL;
+ 	new->colormap = (Color *)NULL;
  	return new;
  }
  
***************
*** 242,247 ****
--- 248,267 ----
  	return text;
  }
  
+ Texture *
+ NewGlossText(gloss)
+ double gloss;
+ {
+ 	Texture *text;
+ 
+ 	text = new_texture(GLOSS);
+ 	/*
+ 	 * Radius of base of cone to be sampled is 1 - glossiness.
+ 	 */
+ 	text->size = 1. - gloss;
+ 	return text;
+ }
+ 
  /*
   * Apply "blotch" texture.
   */
***************
*** 272,278 ****
  
  	val = fBm(pos, text->args[0], text->args[1], (int)text->size);
  	if (val < text->args[4])
! 		val = 0.;
  	else
  		val = text->args[3] + text->args[2] * (val - text->args[4]);
  	if (text->colormap) {
--- 292,298 ----
  
  	val = fBm(pos, text->args[0], text->args[1], (int)text->size);
  	if (val < text->args[4])
! 		val = text->args[3];
  	else
  		val = text->args[3] + text->args[2] * (val - text->args[4]);
  	if (text->colormap) {
***************
*** 363,368 ****
--- 383,416 ----
  		ScaleColor(val, surf->amb, &surf->amb);
  		ScaleColor(val, surf->diff, &surf->diff);
  	}
+ }
+ 
+ GlossText(text, pos, norm, surf)
+ Texture *text;
+ Vector *pos, *norm;
+ Surface *surf;
+ {
+ 	Vector uaxis, vaxis, point, norminc;
+ 
+ 	/*
+ 	 * Find coordinate system with norm as the Z axis.
+ 	 */
+ 	VectCoordSys(norm, &uaxis, &vaxis);
+ 	/*
+ 	 * Find point on unit circle.
+ 	 */
+ 	unit_circle_point(&point);
+ 	/*
+ 	 * Perturb normal appropriately.
+ 	 */
+ 	veccomb(text->size * point.x, uaxis,
+ 		text->size * point.y, vaxis,
+ 		&norminc);
+ 	vecadd(*norm, norminc, norm);
+ 	/*
+ 	 * Renormalize.
+ 	 */
+ 	(void)normalize(norm);
  }
  
  Color *