/* Lighting control functions. */ #include #include #include "polygon.h" /* Ambient lighting intensity */ ModelIntensity AmbientIntensity; /* 1 if ambient shading on, 0 if off */ int AmbientOn; /* Spotlight direction vectors in world and view coordinates. Spotlights are defined in world coordinates, but used in view coordinates. Spotlight directions are reversed in view coordinates, to facilitate incident angle calculations via the dot product */ Point3 SpotDirectionWorld[MAX_SPOTS]; Point3 SpotDirectionView[MAX_SPOTS]; /* Spotlight intensities */ ModelIntensity SpotIntensity[MAX_SPOTS]; /* Spotlight on/off statuses, defaulting to off */ int SpotOn[MAX_SPOTS] = {0, 0, 0}; /* Sets the ambient lighting level. */ void SetAmbientIntensity(ModelIntensity * Intensity) { AmbientIntensity = *Intensity; } /* Returns the ambient lighting level. */ ModelIntensity * GetAmbientIntensity() { return(&AmbientIntensity); } /* Turns ambient shading on */ void TurnAmbientOn() { AmbientOn = 1; } /* Turns ambient shading off */ void TurnAmbientOff() { AmbientOn = 0; } /* Returns the ambient on/off status (1=on, 0=off). */ int GetAmbientState() { return(AmbientOn); } /* Sets the unit vector defining a spotlight's direction. Spotlights are considered to be infinitely far away, so the light rays are parallel and do not vary in angle anywhere in the scene. Vectors are reversed in view space to facilitate angle calculations. The passed-in vector does not have to be a unit vector. */ void SetSpotDirection(int SpotNumber, Point3 * SpotVector) { double Xlen, Ylen, Zlen, Length; if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return; /* bad spot number */ /* Convert the direction vector to a unit vector, so we can do fast shading calculations. First, calculate the length of the vector */ Xlen = FIXED_TO_DOUBLE(SpotVector->X); Ylen = FIXED_TO_DOUBLE(SpotVector->Y); Zlen = FIXED_TO_DOUBLE(SpotVector->Z); Length = sqrt(Xlen*Xlen + Ylen*Ylen + Zlen*Zlen); /* Scale it to a unit vector and offset it from the start point. Flip the vector's direction for use in shading calculations */ SpotDirectionWorld[SpotNumber].X = DOUBLE_TO_FIXED(Xlen/Length); SpotDirectionWorld[SpotNumber].Y = DOUBLE_TO_FIXED(Ylen/Length); SpotDirectionWorld[SpotNumber].Z = DOUBLE_TO_FIXED(Zlen/Length); /* Finally, convert the vector into view space, where we'll actually apply the shading */ XformVec(WorldViewXform, (Fixedpoint *) &SpotDirectionWorld[SpotNumber], (Fixedpoint *) &SpotDirectionView[SpotNumber]); /* Flip the spot direction vector in view space, for ease of shading calculations */ SpotDirectionView[SpotNumber].X = -SpotDirectionView[SpotNumber].X; SpotDirectionView[SpotNumber].Y = -SpotDirectionView[SpotNumber].Y; SpotDirectionView[SpotNumber].Z = -SpotDirectionView[SpotNumber].Z; } /* Sets the intensity of a spotlight. */ void SetSpotIntensity(int SpotNumber, ModelIntensity * Intensity) { ModelIntensity * SpotIntensityPtr; if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return; /* bad spot number */ SpotIntensity[SpotNumber] = *Intensity; } /* Turns on the specified spotlight. */ void TurnSpotOn(int SpotNumber) { if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return; /* bad spot number */ SpotOn[SpotNumber] = 1; } /* Turns off the specified spotlight. */ void TurnSpotOff(int SpotNumber) { if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return; /* bad spot number */ SpotOn[SpotNumber] = 0; } /* Returns a spot's unit direction vector in world space. */ Point3 * GetSpotDirection(int SpotNumber) { if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return(NULL); /* bad spot number */ return(&SpotDirectionWorld[SpotNumber]); } /* Returns a spot's intensity. */ ModelIntensity * GetSpotIntensity(int SpotNumber) { if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return(NULL); /* bad spot number */ return(&SpotIntensity[SpotNumber]); } /* Returns a spot's on/off status (1=on, 0=off). */ int GetSpotState(int SpotNumber) { if ((SpotNumber < 0) || (SpotNumber >= MAX_SPOTS)) return(0); /* bad spot number */ return(SpotOn[SpotNumber]); }