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.