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.