[comp.sources.amiga] v90i255: DKBTrace 2.01 - DKBtrace Ray-Tracer, Part07/10

amiga-request@abcfd20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (09/04/90)

Submitted-by: David Schanen <mtv@milton.u.washington.edu>
Posting-number: Volume 90, Issue 255
Archive-name: applications/dkbtrace-2.01/part07

#!/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 <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 10)."
# Contents:  src/iff.h src/lighting.c
# Wrapped by tadguy@abcfd20 on Mon Sep  3 19:21:21 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/iff.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/iff.h'\"
else
echo shar: Extracting \"'src/iff.h'\" \(20481 characters\)
sed "s/^X//" >'src/iff.h' <<'END_OF_FILE'
X#ifndef IFF_H
X#define IFF_H
X/*----------------------------------------------------------------------*/
X/* IFF.H  defs for IFF-85 Interchange Format Files.	        1/22/86 */
X/*									*/
X/* By Jerry Morrison and Steve Shaw, Electronic Arts.			*/
X/* This software is in the public domain.				*/
X/*----------------------------------------------------------------------*/
X
X#ifndef COMPILER_H
X#include "iff/compiler.h"
X#endif
X
X#ifndef LIBRARIES_DOS_H
X#include "libraries/dos.h"
X#endif
X
X#ifndef OFFSET_BEGINNING
X#define OFFSET_BEGINNING OFFSET_BEGINING
X#endif
X
Xtypedef LONG IFFP;	/* Status code result from an IFF procedure */
X	/* LONG, because must be type compatable with ID for GetChunkHdr.*/
X	/* Note that the error codes below are not legal IDs.*/
X#define IFF_OKAY   0L	/* Keep going...*/
X#define END_MARK  -1L	/* As if there was a chunk at end of group.*/
X#define IFF_DONE  -2L	/* clientProc returns this when it has READ enough.
X			 * It means return thru all levels. File is Okay.*/
X#define DOS_ERROR -3L
X#define NOT_IFF   -4L	/* not an IFF file.*/
X#define NO_FILE   -5L	/* Tried to open file, DOS didn't find it.*/
X#define CLIENT_ERROR -6L /* Client made invalid request, for instance, write
X			 * a negative size chunk.*/
X#define BAD_FORM  -7L	/* A client read proc complains about FORM semantics;
X			 * e.g. valid IFF, but missing a required chunk.*/
X#define SHORT_CHUNK -8L	/* Client asked to IFFReadBytes more bytes than left
X			 * in the chunk. Could be client bug or bad form.*/
X#define BAD_IFF   -9L	/* mal-formed IFF file. [TBD] Expand this into a
X			 * range of error codes.*/
X#define LAST_ERROR BAD_IFF
X
X/* This MACRO is used to RETURN immediately when a termination condition is
X * found. This is a pretty weird macro. It requires the caller to declare a
X * local "IFFP iffp" and assign it. This wouldn't work as a subroutine since
X * it returns for it's caller. */
X#define CheckIFFP()   { if (iffp != IFF_OKAY) return(iffp); }
X
X
X/* ---------- ID -------------------------------------------------------*/
X
Xtypedef LONG ID;	/* An ID is four printable ASCII chars but
X			 * stored as a LONG for efficient copy & compare.*/
X
X/* Four-character IDentifier builder.*/
X#define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )
X
X/* Standard group IDs.  A chunk with one of these IDs contains a
X   SubTypeID followed by zero or more chunks.*/
X#define FORM MakeID('F','O','R','M')
X#define PROP MakeID('P','R','O','P')
X#define LIST MakeID('L','I','S','T')
X#define CAT  MakeID('C','A','T',' ')
X#define FILLER MakeID(' ',' ',' ',' ')
X/* The IDs "FOR1".."FOR9", "LIS1".."LIS9", & "CAT1".."CAT9" are reserved
X * for future standardization.*/
X
X/* Pseudo-ID used internally by chunk reader and writer.*/
X#define NULL_CHUNK 0L	       /* No current chunk.*/
X
X
X/* ---------- Chunk ----------------------------------------------------*/
X
X/* All chunks start with a type ID and a count of the data bytes that 
X   follow--the chunk's "logicl size" or "data size". If that number is odd,
X   a 0 pad byte is written, too. */
Xtypedef struct {
X    ID	  ckID;
X    LONG  ckSize;
X    } ChunkHeader;
X
Xtypedef struct {
X    ID	  ckID;
X    LONG  ckSize;
X    UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
X    } Chunk;
X
X/* Pass ckSize = szNotYetKnown to the writer to mean "compute the size".*/
X#define szNotYetKnown 0x80000001L
X
X/* Need to know whether a value is odd so can word-align.*/
X#define IS_ODD(a)   ((a) & 1)
X
X/* This macro rounds up to an even number. */
X#define WordAlign(size)   ((size+1)&~1)
X
X/* ALL CHUNKS MUST BE PADDED TO EVEN NUMBER OF BYTES.
X * ChunkPSize computes the total "physical size" of a padded chunk from
X * its "data size" or "logical size". */
X#define ChunkPSize(dataSize)  (WordAlign(dataSize) + sizeof(ChunkHeader))
X
X/* The Grouping chunks (LIST, FORM, PROP, & CAT) contain concatenations of
X * chunks after a subtype ID that identifies the content chunks.
X * "FORM type XXXX", "LIST of FORM type XXXX", "PROPerties associated
X * with FORM type XXXX", or "conCATenation of XXXX".*/
Xtypedef struct {
X    ID	  ckID;
X    LONG  ckSize;	/* this ckSize includes "grpSubID".*/
X    ID    grpSubID;
X    } GroupHeader;
X
Xtypedef struct {
X    ID	  ckID;
X    LONG  ckSize;
X    ID    grpSubID;
X    UBYTE grpData[ 1 /*REALLY: ckSize-sizeof(grpSubID)*/ ];
X    } GroupChunk;
X
X
X/* ---------- IFF Reader -----------------------------------------------*/
X
X/******** Routines to support a stream-oriented IFF file reader *******
X *
X * These routines handle lots of details like error checking and skipping
X * over padding. They're also careful not to read past any containing context.
X *
X * These routines ASSUME they're the only ones reading from the file.
X * Client should check IFFP error codes. Don't press on after an error!
X * These routines try to have no side effects in the error case, except
X * partial I/O is sometimes unavoidable.
X *
X * All of these routines may return DOS_ERROR. In that case, ask DOS for the
X * specific error code.
X *
X * The overall scheme for the low level chunk reader is to open a "group read
X * context" with OpenRIFF or OpenRGroup, read the chunks with GetChunkHdr
X * (and its kin) and IFFReadBytes, and close the context with CloseRGroup.
X *
X * The overall scheme for reading an IFF file is to use ReadIFF, ReadIList,
X * and ReadICat to scan the file. See those procedures, ClientProc (below),
X * and the skeleton IFF reader. */
X
X/* Client passes ptrs to procedures of this type to ReadIFF which call them
X * back to handle LISTs, FORMs, CATs, and PROPs.
X *
X * Use the GroupContext ptr when calling reader routines like GetChunkHdr.
X * Look inside the GroupContext ptr for your ClientFrame ptr. You'll
X * want to type cast it into a ptr to your containing struct to get your
X * private contextual data (stacked property settings). See below. */
X#ifdef FDwAT
Xtypedef IFFP ClientProc(struct _GroupContext *);
X#else
Xtypedef IFFP ClientProc();
X#endif
X
X/* Client's context for reading an IFF file or a group.
X * Client should actually make this the first component of a larger struct
X * (it's personal stack "frame") that has a field to store each "interesting"
X * property encountered.
X * Either initialize each such field to a global default or keep a boolean
X * indicating if you've read a property chunk into that field.
X * Your getList and getForm procs should allocate a new "frame" and copy the
X * parent frame's contents. The getProp procedure should store into the frame
X * allocated by getList for the containing LIST. */
Xtypedef struct _ClientFrame {
X   ClientProc *getList, *getProp, *getForm, *getCat;
X    /* client's own data follows; place to stack property settings */
X    } ClientFrame;
X
X/* Our context for reading a group chunk. */
Xtypedef struct _GroupContext {
X    struct _GroupContext *parent; /* Containing group; NULL => whole file. */
X    ClientFrame *clientFrame;     /* Reader data & client's context state. */
X    BPTR file;		/* Byte-stream file handle. */
X    LONG position;	/* The context's logical file position. */
X    LONG bound;		/* File-absolute context bound
X			 * or szNotYetKnown (writer only). */
X    ChunkHeader ckHdr;	/* Current chunk header. ckHdr.ckSize = szNotYetKnown
X			 * means we need to go back and set the size (writer only).
X			 * See also Pseudo-IDs, above. */
X    ID subtype;		/* Group's subtype ID when reading. */
X    LONG bytesSoFar;	/* # bytes read/written of current chunk's data. */
X    } GroupContext;
X
X/* Computes the number of bytes not yet read from the current chunk, given
X * a group read context gc. */
X#define ChunkMoreBytes(gc)  ((gc)->ckHdr.ckSize - (gc)->bytesSoFar)
X
X
X/***** Low Level IFF Chunk Reader *****/
X
X#ifdef FDwAT
X
X/* Given an open file, open a read context spanning the whole file.
X * This is normally only called by ReadIFF.
X * This sets new->clientFrame = clientFrame.
X * ASSUME context allocated by caller but not initialized.
X * ASSUME caller doesn't deallocate the context before calling CloseRGroup.
X * NOT_IFF ERROR if the file is too short for even a chunk header.*/
Xextern IFFP OpenRIFF(BPTR, GroupContext *, ClientFrame *);
X	         /*  file, new,            clientFrame  */
X
X/* Open the remainder of the current chunk as a group read context.
X * This will be called just after the group's subtype ID has been read
X * (automatically by GetChunkHdr for LIST, FORM, PROP, and CAT) so the
X * remainder is a sequence of chunks.
X * This sets new->clientFrame = parent->clientFrame. The caller should repoint
X * it at a new clientFrame if opening a LIST context so it'll have a "stack
X * frame" to store PROPs for the LIST. (It's usually convenient to also
X * allocate a new Frame when you encounter FORM of the right type.)
X *
X * ASSUME new context allocated by caller but not initialized.
X * ASSUME caller doesn't deallocate the context or access the parent context
X * before calling CloseRGroup.
X * BAD_IFF ERROR if context end is odd or extends past parent. */
Xextern IFFP OpenRGroup(GroupContext *, GroupContext *);
X		   /*  parent,         new  */
X
X/* Close a group read context, updating its parent context.
X * After calling this, the old context may be deallocated and the parent
X * context can be accessed again. It's okay to call this particular procedure
X * after an error has occurred reading the group.
X * This always returns IFF_OKAY. */
Xextern IFFP CloseRGroup(GroupContext *);
X		    /*  old  */
X
X/* Skip any remaining bytes of the previous chunk and any padding, then
X * read the next chunk header into context.ckHdr.
X * If the ckID is LIST, FORM, CAT, or PROP, this automatically reads the
X * subtype ID into context->subtype.
X * Caller should dispatch on ckID (and subtype) to an appropriate handler.
X *
X * RETURNS context.ckHdr.ckID (the ID of the new chunk header); END_MARK
X * if there are no more chunks in this context; or NOT_IFF if the top level
X * file chunk isn't a FORM, LIST, or CAT; or BAD_IFF if malformed chunk, e.g.
X * ckSize is negative or too big for containing context, ckID isn't positive,
X * or we hit end-of-file.
X *
X * See also GetFChunkHdr, GetF1ChunkHdr, and GetPChunkHdr, below.*/
Xextern ID       GetChunkHdr(GroupContext *);
X  /*  context.ckHdr.ckID    context  */
X
X/* Read nBytes number of data bytes of current chunk. (Use OpenGroup, etc.
X * instead to read the contents of a group chunk.) You can call this several
X * times to read the data piecemeal.
X * CLIENT_ERROR if nBytes < 0. SHORT_CHUNK if nBytes > ChunkMoreBytes(context)
X * which could be due to a client bug or a chunk that's shorter than it
X * ought to be (bad form). (on either CLIENT_ERROR or SHORT_CHUNK,
X * IFFReadBytes won't read any bytes.) */
Xextern IFFP IFFReadBytes(GroupContext *, BYTE *, LONG);
X		     /*  context,        buffer, nBytes  */
X
X
X/***** IFF File Reader *****/
X
X/* This is a noop ClientProc that you can use for a getList, getForm, getProp,
X * or getCat procedure that just skips the group. A simple reader might just
X * implement getForm, store ReadICat in the getCat field of clientFrame, and
X * use SkipGroup for the getList and getProp procs.*/
Xextern IFFP SkipGroup(GroupContext *);
X
X/* IFF file reader.
X * Given an open file, allocate a group context and use it to read the FORM,
X * LIST, or CAT and it's contents. The idea is to parse the file's contents,
X * and for each FORM, LIST, CAT, or PROP encountered, call the getForm,
X * getList, getCat, or getProp procedure in clientFrame, passing the
X * GroupContext ptr.
X * This is achieved with the aid of ReadIList (which your getList should
X * call) and ReadICat (which your getCat should call, if you don't just use
X * ReadICat for your getCat). If you want to handle FORMs, LISTs, and CATs
X * nested within FORMs, the getForm procedure must dispatch to getForm,
X * getList, and getCat (it can use GetF1ChunkHdr to make this easy).
X *
X * Normal return is IFF_OKAY (if whole file scanned) or IFF_DONE (if a client
X * proc said "done" first).
X * See the skeletal getList, getForm, getCat, and getProp procedures. */
Xextern IFFP ReadIFF(BPTR, ClientFrame *);
X                /*  file, clientFrame  */
X
X/* IFF LIST reader.
X * Your "getList" procedure should allocate a ClientFrame, copy the parent's
X * ClientFrame, and then call this procedure to do all the work.
X *
X * Normal return is IFF_OKAY (if whole LIST scanned) or IFF_DONE (if a client
X * proc said "done" first).
X * BAD_IFF ERROR if a PROP appears after a non-PROP. */
Xextern IFFP ReadIList(GroupContext *, ClientFrame *);
X		  /*  parent,         clientFrame  */
X
X/* IFF CAT reader.
X * Most clients can simply use this to read their CATs. If you must do extra
X * setup work, put a ptr to your getCat procedure in the clientFrame, and
X * have that procedure call ReadICat to do the detail work.
X *
X * Normal return is IFF_OKAY (if whole CAT scanned) or IFF_DONE (if a client
X * proc said "done" first).
X * BAD_IFF ERROR if a PROP appears in the CAT. */
Xextern IFFP ReadICat(GroupContext *);
X		 /*  parent  */
X
X/* Call GetFChunkHdr instead of GetChunkHdr to read each chunk inside a FORM.
X * It just calls GetChunkHdr and returns BAD_IFF if it gets a PROP chunk. */
Xextern ID	GetFChunkHdr(GroupContext *);
X  /*  context.ckHdr.ckID    context  */
X
X/* GetF1ChunkHdr is like GetFChunkHdr, but it automatically dispatches to the
X * getForm, getList, and getCat procedure (and returns the result) if it
X * encounters a FORM, LIST, or CAT. */
Xextern ID	GetF1ChunkHdr(GroupContext *);
X  /*  context.ckHdr.ckID    context  */
X
X/* Call GetPChunkHdr instead of GetChunkHdr to read each chunk inside a PROP.
X * It just calls GetChunkHdr and returns BAD_IFF if it gets a group chunk. */
Xextern ID	GetPChunkHdr(GroupContext *);
X  /*  context.ckHdr.ckID    context  */
X
X#else /* not FDwAT */
X
Xextern IFFP OpenRIFF();
Xextern IFFP OpenRGroup();
Xextern IFFP CloseRGroup();
Xextern ID   GetChunkHdr();
Xextern IFFP IFFReadBytes();
Xextern IFFP SkipGroup();
Xextern IFFP ReadIFF();
Xextern IFFP ReadIList();
Xextern IFFP ReadICat();
Xextern ID   GetFChunkHdr();
Xextern ID   GetF1ChunkHdr();
Xextern ID   GetPChunkHdr();
X
X#endif /* not FDwAT */
X
X/* ---------- IFF Writer -----------------------------------------------*/
X
X/******* Routines to support a stream-oriented IFF file writer *******
X *
X * These routines will random access back to set a chunk size value when the
X * caller doesn't know it ahead of time. They'll also do things automatically
X * like padding and error checking.
X *
X * These routines ASSUME they're the only ones writing to the file.
X * Client should check IFFP error codes. Don't press on after an error!
X * These routines try to have no side effects in the error case, except that
X * partial I/O is sometimes unavoidable.
X *
X * All of these routines may return DOS_ERROR. In that case, ask DOS for the
X * specific error code.
X *
X * The overall scheme is to open an output GroupContext via OpenWIFF or
X * OpenWGroup, call either PutCk or {PutCkHdr {IFFWriteBytes}* PutCkEnd} for
X * each chunk, then use CloseWGroup to close the GroupContext.
X *
X * To write a group (LIST, FORM, PROP, or CAT), call StartWGroup, write out
X * its chunks, then call EndWGroup. StartWGroup automatically writes the
X * group header and opens a nested context for writing the contents.
X * EndWGroup closes the nested context and completes the group chunk. */
X
X
X#ifdef FDwAT
X
X/* Given a file open for output, open a write context.
X * The "limit" arg imposes a fence or upper limit on the logical file
X * position for writing data in this context. Pass in szNotYetKnown to be
X * bounded only by disk capacity.
X * ASSUME new context structure allocated by caller but not initialized.
X * ASSUME caller doesn't deallocate the context before calling CloseWGroup.
X * The caller is only allowed to write out one FORM, LIST, or CAT in this top
X * level context (see StartWGroup and PutCkHdr).
X * CLIENT_ERROR if limit is odd.*/
Xextern IFFP OpenWIFF(BPTR, GroupContext *, LONG);
X		 /*  file, new,            limit {file position}  */
X
X/* Start writing a group (presumably LIST, FORM, PROP, or CAT), opening a
X * nested context. The groupSize includes all nested chunks + the subtype ID.
X *
X * The subtype of a LIST or CAT is a hint at the contents' FORM type(s). Pass
X * in FILLER if it's a mixture of different kinds.
X *
X * This writes the chunk header via PutCkHdr, writes the subtype ID via
X * IFFWriteBytes, and calls OpenWGroup. The caller may then write the nested
X * chunks and finish by calling EndWGroup.
X * The OpenWGroup call sets new->clientFrame = parent->clientFrame.
X *
X * ASSUME new context structure allocated by caller but not initialized.
X * ASSUME caller doesn't deallocate the context or access the parent context
X * before calling CloseWGroup.
X * ERROR conditions: See PutCkHdr, IFFWriteBytes, OpenWGroup. */
Xextern IFFP StartWGroup(GroupContext *, ID, LONG, ID, GroupContext *);
X		    /*  parent, groupType, groupSize, subtype, new  */
X
X/* End a group started by StartWGroup.
X * This just calls CloseWGroup and PutCkEnd.
X * ERROR conditions: See CloseWGroup and PutCkEnd. */
Xextern IFFP EndWGroup(GroupContext *);
X		    /*  old  */
X
X/* Open the remainder of the current chunk as a group write context.
X * This is normally only called by StartWGroup.
X *
X * Any fixed limit to this group chunk or a containing context will impose
X * a limit on the new context.
X * This will be called just after the group's subtype ID has been written
X * so the remaining contents will be a sequence of chunks.
X * This sets new->clientFrame = parent->clientFrame.
X * ASSUME new context structure allocated by caller but not initialized.
X * ASSUME caller doesn't deallocate the context or access the parent context
X * before calling CloseWGroup.
X * CLIENT_ERROR if context end is odd or PutCkHdr wasn't called first. */
Xextern IFFP OpenWGroup(GroupContext *, GroupContext *);
X		   /*  parent,         new  */
X
X/* Close a write context and update its parent context.
X * This is normally only called by EndWGroup.
X *
X * If this is a top level context (created by OpenWIFF) we'll set the file's
X * EOF (end of file) but won't close the file.
X * After calling this, the old context may be deallocated and the parent
X * context can be accessed again.
X *
X * Amiga DOS Note: There's no call to set the EOF. We just position to the
X * desired end and return. Caller must Close file at that position.
X * CLIENT_ERROR if PutCkEnd wasn't called first. */
Xextern IFFP CloseWGroup(GroupContext *);
X		    /*  old  */
X
X/* Write a whole chunk to a GroupContext. This writes a chunk header, ckSize
X * data bytes, and (if needed) a pad byte. It also updates the GroupContext.
X * CLIENT_ERROR if ckSize == szNotYetKnown. See also PutCkHdr errors. */
Xextern IFFP PutCk(GroupContext *, ID,   LONG,   BYTE *);
X	      /*  context,        ckID, ckSize, *data  */
X
X/* Write just a chunk header. Follow this will any number of calls to
X * IFFWriteBytes and finish with PutCkEnd.
X * If you don't yet know how big the chunk is, pass in ckSize = szNotYetKnown,
X * then PutCkEnd will set the ckSize for you later.
X * Otherwise, IFFWriteBytes and PutCkEnd will ensure that the specified
X * number of bytes get written.
X * CLIENT_ERROR if the chunk would overflow the GroupContext's bound, if
X * PutCkHdr was previously called without a matching PutCkEnd, if ckSize < 0
X * (except szNotYetKnown), if you're trying to write something other
X * than one FORM, LIST, or CAT in a top level (file level) context, or
X * if ckID <= 0 (these illegal ID values are used for error codes). */
Xextern IFFP PutCkHdr(GroupContext *, ID,   LONG);
X		 /*  context,        ckID, ckSize  */
X
X/* Write nBytes number of data bytes for the current chunk and update
X * GroupContext.
X * CLIENT_ERROR if this would overflow the GroupContext's limit or the
X * current chunk's ckSize, or if PutCkHdr wasn't called first, or if
X * nBytes < 0. */
Xextern IFFP IFFWriteBytes(GroupContext *, BYTE *, LONG);
X		      /*  context,        *data,  nBytes  */
X
X/* Complete the current chunk, write a pad byte if needed, and update
X * GroupContext.
X * If current chunk's ckSize = szNotYetKnown, this goes back and sets the
X * ckSize in the file.
X * CLIENT_ERROR if PutCkHdr wasn't called first, or if client hasn't
X * written 'ckSize' number of bytes with IFFWriteBytes. */
Xextern IFFP PutCkEnd(GroupContext *);
X		 /*  context  */
X
X#else /* not FDwAT */
X
Xextern IFFP OpenWIFF();
Xextern IFFP StartWGroup();
Xextern IFFP EndWGroup();
Xextern IFFP OpenWGroup();
Xextern IFFP CloseWGroup();
Xextern IFFP PutCk();
Xextern IFFP PutCkHdr();
Xextern IFFP IFFWriteBytes();
Xextern IFFP PutCkEnd();
X
X#endif /* not FDwAT */
X
X#endif IFF_H
X
END_OF_FILE
if test 20481 -ne `wc -c <'src/iff.h'`; then
    echo shar: \"'src/iff.h'\" unpacked with wrong size!
fi
# end of 'src/iff.h'
fi
if test -f 'src/lighting.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/lighting.c'\"
else
echo shar: Extracting \"'src/lighting.c'\" \(18901 characters\)
sed "s/^X//" >'src/lighting.c' <<'END_OF_FILE'
X/*****************************************************************************
X*
X*                                    lighting.c
X*
X*   from DKBTrace (c) 1990  David Buck
X*
X*  This module calculates lighting properties like ambient, diffuse, specular,
X*  reflection, refraction, etc.
X*
X*
X* This software is freely distributable. The source and/or object code may be
X* copied or uploaded to communications services so long as this notice remains
X* at the top of each file.  If any changes are made to the program, you must
X* clearly indicate in the documentation and in the programs startup message
X* who it was who made the changes. The documentation should also describe what
X* those changes were. This software may not be included in whole or in
X* part into any commercial package without the express written consent of the
X* author.  It may, however, be included in other public domain or freely
X* distributed software so long as the proper credit for the software is given.
X*
X* This software is provided as is without any guarantees or warranty. Although
X* the author has attempted to find and correct any bugs in the software, he
X* is not responsible for any damage caused by the use of the software.  The
X* author is under no obligation to provide service, corrections, or upgrades
X* to this package.
X*
X* Despite all the legal stuff above, if you do find bugs, I would like to hear
X* about them.  Also, if you have any comments or questions, you may contact me
X* at the following address:
X*
X*     David Buck
X*     22C Sonnet Cres.
X*     Nepean Ontario
X*     Canada, K2H 8W7
X*
X*  I can also be reached on the following bulleton boards:
X*
X*     ATX              (613) 526-4141
X*     OMX              (613) 731-3419
X*     Mystic           (613) 731-0088 or (613) 731-6698
X*
X*  Fidonet:   1:163/109.9
X*  Internet:  David_Buck@Carleton.CA
X*
X*  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
X*
X*     Lattice BBS                      (708) 916-1200
X*     The Information Exchange BBS     (708) 945-5575
X*     Stillwaters BBS                  (708) 403-2826
X*
X*****************************************************************************/
X
X
X#include "frame.h"
X#include "vector.h"
X#include "dkbproto.h"
X
Xextern int Trace_Level;
Xextern FRAME Frame;
Xextern unsigned long Options;
Xextern int Quality;
Xextern long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
Xextern long Reflected_Rays_Traced, Refracted_Rays_Traced;
Xextern long Transmitted_Rays_Traced;
X
X#define Small_Tolerance 0.001
X
Xvoid Colour_At (Colour, Object, Intersection_Point)
X   COLOUR *Colour;
X   OBJECT *Object;
X   VECTOR *Intersection_Point;
X   {
X   register DBL x, y, z;
X   VECTOR Transformed_Point;
X
X   if (Object -> Object_Texture->Texture_Transformation) {
X      MInverseTransformVector (&Transformed_Point,
X                               Intersection_Point,
X			       Object -> Object_Texture->Texture_Transformation);
X      }
X   else
X      Transformed_Point = *Intersection_Point;
X
X   x = Transformed_Point.x;
X   y = Transformed_Point.y;
X   z = Transformed_Point.z;
X     
X   switch (Object -> Object_Texture->Texture_Number) {
X      case BOZO_TEXTURE: 
X           Bozo (x, y, z, Object, Colour);
X           break;
X
X      case MARBLE_TEXTURE:
X           marble (x, y, z, Object, Colour);
X           break;
X
X      case WOOD_TEXTURE:
X           wood (x, y, z, Object, Colour);
X           break;
X
X      case CHECKER_TEXTURE:
X           checker (x, y, z, Object, Colour);
X           break;
X
X      case SPOTTED_TEXTURE:
X           spotted (x, y, z, Object, Colour);
X           break;
X
X      case AGATE_TEXTURE:
X           agate (x, y, z, Object, Colour);
X           break;
X
X      case GRANITE_TEXTURE:
X           granite (x, y, z, Object, Colour);
X           break;
X
X     case GRADIENT_TEXTURE:
X           gradient (x, y, z, Object, Colour);
X           break;
X
X      case IMAGEMAP_TEXTURE:
X           texture_map (x, y, z, Object, Colour);
X	   break;
X
X      default:
X           *Colour = Object -> Object_Colour;
X           break;
X      }
X   }
X
X
Xvoid Perturb_Normal(New_Normal, Object, Intersection_Point, Surface_Normal)
X   VECTOR *New_Normal, *Intersection_Point, *Surface_Normal;
X   OBJECT *Object;
X   {
X   VECTOR Transformed_Point;
X   register DBL x, y, z;
X
X   if (Object -> Object_Texture->Bump_Number == NO_BUMPS) {
X      *New_Normal = *Surface_Normal;
X      return;
X      }
X
X   if (Object -> Object_Texture->Texture_Transformation)
X      MInverseTransformVector (&Transformed_Point,
X                               Intersection_Point,
X                               Object -> Object_Texture->Texture_Transformation);
X   else
X      Transformed_Point = *Intersection_Point;
X
X   x = Transformed_Point.x;
X   y = Transformed_Point.y;
X   z = Transformed_Point.z;
X
X   switch (Object -> Object_Texture->Bump_Number) {
X      case NO_BUMPS: break;
X
X      case WAVES: waves (x, y, z, Object, New_Normal);
X                  break;
X
X      case RIPPLES: ripples (x, y, z, Object, New_Normal);
X                  break;
X
X      case WRINKLES: wrinkles (x, y, z, Object, New_Normal);
X                  break;
X
X      case BUMPS: bumps (x, y, z, Object, New_Normal);
X                  break;
X
X      case DENTS: dents (x, y, z, Object, New_Normal);
X                  break;
X      }
X   return;
X   }
X
Xvoid Ambient (Object, Intersection_Point, Surface_Colour, Colour)
X   OBJECT *Object;
X   VECTOR *Intersection_Point;
X   COLOUR *Surface_Colour;
X   COLOUR *Colour;
X   {
X   DBL t;
X
X   if (Object -> Object_Texture -> Object_Ambient == 0.0)
X      return;
X
X   t = 1.0 - Surface_Colour->Alpha;
X   Colour->Red += Surface_Colour->Red * t * Object->Object_Texture->Object_Ambient;
X   Colour->Green += Surface_Colour->Green * t * Object->Object_Texture->Object_Ambient;
X   Colour->Blue += Surface_Colour->Blue * t * Object->Object_Texture->Object_Ambient;
X   return;
X   }
X
X
Xvoid Diffuse (Object, Intersection_Point, Eye, Surface_Normal, Surface_Colour, Colour)
X   OBJECT *Object;
X   VECTOR *Intersection_Point, *Surface_Normal;
X   COLOUR *Surface_Colour;
X   COLOUR *Colour;
X   RAY *Eye;
X   {
X   DBL Cos_Angle_Of_Incidence, Halfway_Length, Normal_Length;
X   DBL Intensity, RandomNumber, Light_Source_Depth;
X   RAY Light_Source_Ray;
X   OBJECT *Light_Source, *Blocking_Object;
X   int Intersection_Found;
X   INTERSECTION *Local_Intersection;
X   VECTOR Halfway, REye, Local_Normal, Normal_Projection, Reflect_Direction;
X   COLOUR Light_Colour, Blocking_Colour;
X   PRIOQ *Local_Queue;
X
X   if ((Object -> Object_Texture -> Object_Diffuse == 0.0) &&
X       (Object -> Object_Texture -> Object_Specular == 0.0) &&
X       (Object -> Object_Texture -> Object_Phong == 0.0))
X     return;
X
X   if (Object -> Object_Texture -> Object_Specular != 0.0)
X      {
X      REye.x = -Eye->Direction.x;
X      REye.y = -Eye->Direction.y;
X      REye.z = -Eye->Direction.z;
X      }
X
X   Local_Queue = pq_new (128);
X
X   for (Light_Source = Frame.Light_Sources ; 
X        Light_Source != NULL;
X        Light_Source = Light_Source -> Next_Light_Source)
X      {
X      Intersection_Found = FALSE;  
X      Light_Source_Ray.Initial = *Intersection_Point;
X      Light_Source_Ray.Quadric_Constants_Cached = FALSE;
X      Light_Colour = Light_Source->Object_Colour;
X
X      VSub (Light_Source_Ray.Direction,
X           Light_Source->Object_Center,
X	   *Intersection_Point);
X
X      VLength (Light_Source_Depth, Light_Source_Ray.Direction);
X
X      VScale (Light_Source_Ray.Direction, Light_Source_Ray.Direction,
X                1.0/Light_Source_Depth);
X
X    /* What objects does this ray intersect? */
X      if (Quality > 3)
X         for (Blocking_Object = Frame.Objects ; 
X              Blocking_Object != NULL ;
X              Blocking_Object = Blocking_Object -> Next_Object) {
X
X            Shadow_Ray_Tests++;
X            if (Blocking_Object == Light_Source)
X               continue;
X
X            for (All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Queue) ;
X                 (Local_Intersection = pq_get_highest(Local_Queue)) != NULL ;
X                 pq_delete_highest(Local_Queue)) {
X
X               if ((Local_Intersection -> Depth < Light_Source_Depth-Small_Tolerance)
X                    && (Local_Intersection -> Depth > Small_Tolerance))
X                  {
X                  Shadow_Rays_Succeeded++;
X                  if (Blocking_Object->Transparency) {
X                     Make_Colour(&Blocking_Colour, 0.0, 0.0, 0.0);
X                     Colour_At(&Blocking_Colour, Blocking_Object, &Local_Intersection->Point);
X                     Light_Colour.Red *= 
X                                    Blocking_Colour.Red * Blocking_Colour.Alpha;
X                     Light_Colour.Green *= 
X                                    Blocking_Colour.Green * Blocking_Colour.Alpha;
X                     Light_Colour.Blue *=
X                                    Blocking_Colour.Blue * Blocking_Colour.Alpha;
X                     }
X                  else {
X                     Intersection_Found = TRUE;
X                     break;
X                     }
X                  }
X               }
X            if (Intersection_Found) {
X               while (pq_get_highest(Local_Queue))
X                  pq_delete_highest(Local_Queue);
X               break;
X               }
X            }
X
X      if (!Intersection_Found)
X         {
X         if (Object->Object_Texture->Object_Phong)      /* Phong Specular Highlight rtn. */
X	    {
X            VDot(Cos_Angle_Of_Incidence, Eye->Direction, *Surface_Normal);
X            if (Cos_Angle_Of_Incidence < 0.0)
X               {
X               Local_Normal = *Surface_Normal;
X               Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
X               }
X            else
X               VScale (Local_Normal, *Surface_Normal, -1.0);
X
X            VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
X            VScale (Normal_Projection, Normal_Projection, 2.0);
X            VAdd (Reflect_Direction, Eye->Direction, Normal_Projection);
X
X            VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray.Direction);
X            VLength (Normal_Length, Light_Source_Ray.Direction);
X            Cos_Angle_Of_Incidence /= Normal_Length;
X
X            if (Cos_Angle_Of_Incidence < 0.0)
X               Cos_Angle_Of_Incidence = 0;
X
X            if (Object -> Object_Texture -> Object_PhongSize != 1.0)
X               Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_PhongSize);
X            else
X               Intensity = Cos_Angle_Of_Incidence;
X
X            Intensity *= Object -> Object_Texture -> Object_Phong;
X
X            Colour->Red+=Intensity*(Light_Colour.Red);
X            Colour->Green+=Intensity*(Light_Colour.Green);
X            Colour->Blue+=Intensity*(Light_Colour.Blue);
X            }
X
X         if (Object->Object_Texture->Object_Specular > 0.0)   /* better specular highlights */
X            {
X            VHalf (Halfway, REye, Light_Source_Ray.Direction);
X            VLength (Normal_Length, *Surface_Normal);
X            VLength (Halfway_Length, Halfway);
X            VDot (Cos_Angle_Of_Incidence, Halfway, *Surface_Normal);
X            Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
X
X            if (Cos_Angle_Of_Incidence < 0.0)
X               Cos_Angle_Of_Incidence = 0;
X
X            if (Object -> Object_Texture -> Object_Roughness != 1.0)
X               Intensity = pow(Cos_Angle_Of_Incidence, 1 / Object->Object_Texture->Object_Roughness);
X            else
X               Intensity = Cos_Angle_Of_Incidence;
X
X            Intensity *= Object->Object_Texture->Object_Specular;
X
X            Colour->Red+=Intensity* (Light_Colour.Red);
X            Colour->Green+=Intensity* (Light_Colour.Green);
X            Colour->Blue+=Intensity* (Light_Colour.Blue);
X            }
X
X         if (Object->Object_Texture->Object_Diffuse > 0.0)      /* now do normal diffuse */
X            {
X            VDot (Cos_Angle_Of_Incidence, *Surface_Normal, Light_Source_Ray.Direction);
X            if (Cos_Angle_Of_Incidence < 0.0)
X               Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
X	
X            if (Object -> Object_Texture -> Object_Brilliance != 1.0)
X               Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_Brilliance);
X	    else
X               Intensity = Cos_Angle_Of_Incidence;
X
X            Intensity *= Object -> Object_Texture -> Object_Diffuse;
X
X            RandomNumber = (rand()&0x7FFF)/(DBL) 0x7FFF;
X
X            Intensity -= RandomNumber * Object->Object_Texture->Texture_Randomness;
X
X            Intensity *= 1.0 - Surface_Colour->Alpha;
X	    Colour->Red += Intensity * (Surface_Colour->Red) * (Light_Colour.Red);
X            Colour->Green += Intensity * (Surface_Colour->Green) * (Light_Colour.Green);
X            Colour->Blue += Intensity * (Surface_Colour->Blue) * (Light_Colour.Blue);
X	    }
X         }
X      }
X   pq_free (Local_Queue);
X   return;
X   }
X
Xvoid Transmit (Object, Intersection_Point, Ray, Surface_Normal, Surface_Colour, Colour)
X   OBJECT *Object;
X   VECTOR *Intersection_Point;
X   RAY *Ray;
X   VECTOR *Surface_Normal;
X   COLOUR *Surface_Colour;
X   COLOUR *Colour;
X   {
X   RAY New_Ray;
X   COLOUR Temp_Colour;
X
X   if (Surface_Colour->Alpha == 0.0)
X      return;
X
X   New_Ray.Initial = *Intersection_Point;
X   New_Ray.Direction = Ray->Direction;
X
X   Copy_Ray_Containers (&New_Ray, Ray);
X   Trace_Level++;
X   Transmitted_Rays_Traced++;
X   Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
X   New_Ray.Quadric_Constants_Cached = FALSE;
X   Trace (&New_Ray, &Temp_Colour);
X   Trace_Level--;
X   (Colour -> Red) += Temp_Colour.Red * Surface_Colour->Red * Surface_Colour->Alpha;
X   (Colour -> Green) += Temp_Colour.Green * Surface_Colour->Green * Surface_Colour->Alpha;
X   (Colour -> Blue) += Temp_Colour.Blue * Surface_Colour->Blue * Surface_Colour->Alpha;
X   }
X
X
Xvoid Reflect (Object, Intersection_Point, Ray, Surface_Normal, Colour)
X   OBJECT *Object;
X   VECTOR *Intersection_Point;
X   RAY *Ray;
X   VECTOR *Surface_Normal;
X   COLOUR *Colour;
X   {
X   RAY New_Ray;
X   COLOUR Temp_Colour;
X   VECTOR Local_Normal;
X   VECTOR Normal_Projection;
X   register DBL Normal_Component;
X
X   if (Object -> Object_Texture -> Object_Reflection != 0.0)
X      {
X      Reflected_Rays_Traced++;
X      VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
X      if (Normal_Component < 0.0) {
X         Local_Normal = *Surface_Normal;
X         Normal_Component *= -1.0;
X         }
X      else
X         VScale (Local_Normal, *Surface_Normal, -1.0);
X
X      VScale (Normal_Projection, Local_Normal, Normal_Component);
X      VScale (Normal_Projection, Normal_Projection, 2.0);
X      VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
X      New_Ray.Initial = *Intersection_Point;
X
X      Copy_Ray_Containers (&New_Ray, Ray);
X      Trace_Level++;
X      Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
X      New_Ray.Quadric_Constants_Cached = FALSE;
X      Trace (&New_Ray, &Temp_Colour);
X      Trace_Level--;
X      (Colour -> Red) += (Temp_Colour.Red) 
X                             * (Object -> Object_Texture -> Object_Reflection);
X      (Colour -> Green) += (Temp_Colour.Green)
X                             * (Object -> Object_Texture -> Object_Reflection);
X      (Colour -> Blue) += (Temp_Colour.Blue)
X                             * (Object -> Object_Texture -> Object_Reflection);
X      }
X   }
X
Xvoid Refract (Object, Intersection_Point, Ray, Surface_Normal, Colour)
X   OBJECT *Object;
X   VECTOR *Intersection_Point;
X   RAY *Ray;
X   VECTOR *Surface_Normal;
X   COLOUR *Colour;
X   {
X   RAY New_Ray;
X   COLOUR Temp_Colour;
X   VECTOR Local_Normal;
X   VECTOR Normal_Projection;
X   register DBL Normal_Component, Temp_IOR;
X
X   if (Object -> Object_Texture -> Object_Refraction != 0.0)
X      {
X      Refracted_Rays_Traced++;
X      VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
X      if (Normal_Component >= 0.0)
X         {
X         VScale (Local_Normal, *Surface_Normal, -1.0);
X         }
X      else
X         {
X         Local_Normal.x = Surface_Normal -> x;
X         Local_Normal.y = Surface_Normal -> y;
X         Local_Normal.z = Surface_Normal -> z;
X
X         Normal_Component *= -1.0;
X         }
X
X      VScale (Normal_Projection, Local_Normal, Normal_Component);
X      VAdd (Normal_Projection, Normal_Projection, Ray -> Direction);
X      Copy_Ray_Containers (&New_Ray, Ray);
X
X      if (Ray -> Containing_Index == -1)
X         {
X       /* The ray is entering from the atmosphere */
X         Ray_Enter (&New_Ray, Object);
X
X         VScale (Normal_Projection, Normal_Projection,
X               (Frame.Atmosphere_IOR)/(Object -> Object_Texture -> Object_Index_Of_Refraction));
X         }
X      else
X         {
X       /* The ray is currently inside an object */
X         if (New_Ray.Containing_Objects [New_Ray.Containing_Index] == Object)
X            {
X          /* The ray is leaving the current object */
X            Ray_Exit (&New_Ray);
X            if (New_Ray.Containing_Index == -1)
X             /* The ray is leaving into the atmosphere */
X               Temp_IOR = Frame.Atmosphere_IOR;
X            else
X             /* The ray is leaving into another object */
X               Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
X
X            VScale (Normal_Projection, Normal_Projection,
X               (Object -> Object_Texture -> Object_Index_Of_Refraction) / Temp_IOR);
X            }
X         else
X            {
X            /* The ray is entering a new object */
X            Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
X            Ray_Enter (&New_Ray, Object);
X
X            VScale (Normal_Projection, Normal_Projection,
X                 Temp_IOR/(Object -> Object_Texture -> Object_Index_Of_Refraction));
X
X            }
X         }
X
X      VScale (Local_Normal, Local_Normal, -1.0);
X      VAdd (New_Ray.Direction, Local_Normal, Normal_Projection);
X      VNormalize (New_Ray.Direction, New_Ray.Direction);
X      New_Ray.Initial = *Intersection_Point;
X      Trace_Level++;
X      Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
X      New_Ray.Quadric_Constants_Cached = FALSE;
X      Trace (&New_Ray, &Temp_Colour);
X      Trace_Level--;
X      (Colour -> Red) += (Temp_Colour.Red)
X                        * (Object -> Object_Texture -> Object_Refraction);
X      (Colour -> Green) += (Temp_Colour.Green)
X                        * (Object -> Object_Texture -> Object_Refraction);
X      (Colour -> Blue) += (Temp_Colour.Blue)
X                        * (Object -> Object_Texture -> Object_Refraction);
X      }  
X   }
X
Xvoid Fog (Distance, Fog_Colour, Fog_Distance, Colour)
X   DBL Distance, Fog_Distance;
X   COLOUR *Fog_Colour, *Colour;
X   {
X   DBL Fog_Factor, Fog_Factor_Inverse;
X
X   Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
X   Fog_Factor_Inverse = 1.0 - Fog_Factor;
X   Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
X   Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
X   Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
X   }
END_OF_FILE
if test 18901 -ne `wc -c <'src/lighting.c'`; then
    echo shar: \"'src/lighting.c'\" unpacked with wrong size!
fi
# end of 'src/lighting.c'
fi
echo shar: End of archive 7 \(of 10\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 10 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
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.