Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

sprite.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  SPRITE.C                                                                            */
00003 /*                                                                                      */
00004 /*  Author: Michael R. Brumm                                                              */
00005 /*  Description: Sprite implementation                                                  */
00006 /*                                                                                      */
00007 /*  The contents of this file are subject to the Genesis3D Public License               */
00008 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00009 /*  compliance with the License. You may obtain a copy of the License at                */
00010 /*  http://www.genesis3d.com                                                            */
00011 /*                                                                                      */
00012 /*  Software distributed under the License is distributed on an "AS IS"                 */
00013 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00014 /*  the License for the specific language governing rights and limitations              */
00015 /*  under the License.                                                                  */
00016 /*                                                                                      */
00017 /****************************************************************************************/
00018 
00019 #include <assert.h>
00020 #include <math.h>
00021 
00022 #include "world.h"
00023 #include "trace.h"
00024 
00025 #include "sprite.h"
00026 
00027 #include "ErrorLog.h"
00028 
00029 
00030 #define BIG_DISTANCE 30000.0f
00031 
00032 extern geBoolean geBitmap_IsValid(const geBitmap *Bmp);
00033 
00034 // sprites are rectangular
00035 #define SPRITE_NUM_CORNERS 4
00036 
00037 // unit corners used to create scaled corners
00038 #define UNIT_CORNERS    { {0.5f, -0.5f}, {-0.5f, -0.5f}, {-0.5f, 0.5f}, {0.5f, 0.5f} }
00039 const geCoordinate      UnitCorners[SPRITE_NUM_CORNERS] = UNIT_CORNERS;
00040 
00041 
00042 // dynamic light information is reused between sprites
00043 // saving resources and allocation time
00044 typedef struct geSprite_DynamicLight
00045 {
00046         geVec3d         Normal;
00047         geColor         Color;
00048         geFloat         Distance;
00049         geFloat         Radius;
00050 } geSprite_DynamicLight;
00051 
00052 static geSprite_DynamicLight geSpriteDynamicLights[MAX_DYNAMIC_LIGHTS];
00053 
00054 
00055 // frustum clipping arrays are reused between sprites
00056 // saving resources and allocation time
00057 #define MAX_TEMP_VERTS  30
00058 
00059 static Surf_TexVert             UnclippedUVRGBA[MAX_TEMP_VERTS];
00060 
00061 static geVec3d                          FrustumClippedVertexes1[MAX_TEMP_VERTS];
00062 static Surf_TexVert             FrustumClippedUVRGBA1[MAX_TEMP_VERTS];
00063 static geVec3d                          FrustumClippedVertexes2[MAX_TEMP_VERTS];
00064 static Surf_TexVert             FrustumClippedUVRGBA2[MAX_TEMP_VERTS];
00065 
00066 static int32                                    FrustumNumClippedTexturedLitVertices;
00067 
00068 static Surf_TLVertex    FrustumClippedTexturedLitVertexes[MAX_TEMP_VERTS];
00069 
00070 
00071 typedef struct geSprite
00072 {
00073         // number of owners
00074         int32                           RefCount;                               
00075 
00076         // bitmaps used to texture the sprite
00077         geBitmap *      Bitmap;
00078         geBitmap *      BackfaceBitmap;
00079 
00080         // backface properties
00081         geBoolean               BackfaceEnabled;
00082         geBoolean               BackfaceMirrorImage;
00083 
00084         // makes the sprite always face the camera
00085         geBoolean               AlwaysFaceCamera;
00086 
00087         // transform affects position and orientation of the sprite
00088         geXForm3d               Transform;
00089 
00090         // internal transform also affects position and orientation of the sprite
00091         // allows the sprite to be offset from its center of rotation
00092         geBoolean               InternalTransformUsed;
00093         geXForm3d               InternalTransform;
00094 
00095         // actual center of sprite (both external and internal transforms added)
00096         geVec3d                 Position;
00097 
00098         // scale of the sprite
00099         // allows sprite to be sized without changing
00100         geFloat                 ScaleX;
00101         geFloat                 ScaleY;
00102 
00103         // cached corners and vertexes
00104         // corners are used to build the vertexes
00105         // vertexes are used to build final screen polys
00106         geCoordinate    Corners[SPRITE_NUM_CORNERS];
00107         geVec3d                         Vertexes[SPRITE_NUM_CORNERS];
00108 
00109         // texture parameters
00110         geFloat                 TextureOffsetX;
00111         geFloat                 TextureOffsetY;
00112         geFloat                 TextureScaleX;
00113         geFloat                 TextureScaleY;
00114 
00115         // cached texture mapping information
00116         geUV                            UVs[SPRITE_NUM_CORNERS];
00117         geUV                            BackfaceUVs[SPRITE_NUM_CORNERS];
00118 
00119         // lighting parameters
00120         // used to build cached lighting information
00121         geColor                 AmbientLight;
00122         geBoolean               UseFillLight;
00123         geColor                 FillLight;
00124         geVec3d                 FillLightNormal;
00125         geBoolean               UseLightFromFloor;
00126         int32                           MaximumDynamicLightsToUse;
00127 
00128         // cached lighting information
00129         GE_RGBA                 RGBA;
00130         GE_RGBA                 BackfaceRGBA;
00131 
00132         // surface normal of the sprite's face
00133         geVec3d                 SurfaceNormal;
00134         geBoolean               LightingUsesSurfaceNormal;
00135 
00136         // bounding box which other objects collide against
00137         geVec3d                 BoundingBoxMinCorner;
00138         geVec3d                 BoundingBoxMaxCorner;
00139 
00140         // user data
00141         void *                  UserData;
00142 
00143         // tracks changes made and whether cached data needs
00144         // to be updated
00145         geBoolean               TransformChanged;
00146         geBoolean               LightingChanged;
00147 
00148 } geSprite;
00149 
00150 
00151         // these are useful globals to monitor resources
00152 int32 geSprite_Count       = 0;
00153 int32 geSprite_RefCount    = 0;
00154 
00155 
00156 __inline static void geSprite_UpdatePosition(geSprite *S)
00157 {
00158         if (S->AlwaysFaceCamera)
00159                 S->Position = S->Transform.Translation;
00160         else
00161                 geVec3d_Add( &(S->Transform.Translation), &(S->InternalTransform.Translation), &(S->Position) );
00162 }
00163 
00164 
00165 __inline static void geSprite_UpdateCorners(geSprite *S)
00166 {
00167         int i;
00168 
00169         for (i = 0; i < SPRITE_NUM_CORNERS; i++)
00170         {
00171                 S->Corners[i].X = UnitCorners[i].X * S->ScaleX;
00172                 S->Corners[i].Y = UnitCorners[i].Y * S->ScaleY;
00173         }
00174 }
00175 
00176 
00177 __inline static void geSprite_UpdateVertexes(geSprite *S)
00178 {
00179         int i;
00180 
00181         // create a rectangle of the correct size around the origin
00182         for (i = 0; i < SPRITE_NUM_CORNERS; i++)
00183         {
00184                 S->Vertexes[i].X = S->Corners[i].X;
00185                 S->Vertexes[i].Y = S->Corners[i].Y;
00186                 S->Vertexes[i].Z = 0.0f;
00187         }
00188 
00189         // apply the internal and external transform if an internal transform is used
00190         if (S->InternalTransformUsed)
00191                 geXForm3d_TransformArray(&(S->InternalTransform), S->Vertexes, S->Vertexes, SPRITE_NUM_CORNERS);
00192 
00193         // apply the sprites external transform
00194         geXForm3d_TransformArray(&(S->Transform), S->Vertexes, S->Vertexes, SPRITE_NUM_CORNERS);
00195 }
00196 
00197 
00198 __inline static void geSprite_UpdateVertexesToFaceCamera(geSprite *S, geCamera *Camera)
00199 {
00200         int i;
00201         const geXForm3d *CameraXForm;
00202         geVec3d Left;
00203         geVec3d Up;
00204         geVec3d In;
00205         geFloat Dot;
00206 
00207         // optimized out:
00208         //
00209         //              geXForm3d FaceCameraXForm;
00210 
00211         // get the camera's transform
00212         CameraXForm = geCamera_GetWorldSpaceXForm(Camera);
00213 
00214         // get the vector opposite to the direction the camera is looking
00215         //
00216         // optimized from:
00217         //
00218         //              geXForm3d_GetIn(CameraXForm, &In);
00219         //              In.X = -In.X;
00220         //              In.Y = -In.Y;
00221         //              In.Z = -In.Z;
00222         //
00223         In.X = CameraXForm->AZ;
00224         In.Y = CameraXForm->BZ;
00225         In.Z = CameraXForm->CZ;
00226 
00227         // get the up direction of the camera
00228         geXForm3d_GetUp(CameraXForm, &Up);
00229 
00230         Dot = geVec3d_DotProduct(&Up, &In);
00231 
00232         Up.X = Up.X - (Dot * In.X);
00233         Up.Y = Up.Y - (Dot * In.Y);
00234         Up.Z = Up.Z - (Dot * In.Z);
00235 
00236         geVec3d_Normalize(&Up);
00237 
00238         // get the left vector direction for the sprite based on the 'in' and 'up'
00239         //
00240         // optimized from:
00241         //
00242         //              geVec3d_CrossProduct(&Up, &In, &Left);
00243         //
00244         Left.X = (Up.Z * In.Y) - (Up.Y * In.Z);
00245   Left.Y = (Up.X * In.Z) - (Up.Z * In.X);
00246   Left.Z = (Up.Y * In.X) - (Up.X * In.Y);
00247 
00248         // build the transform based on the left, up, in, and position of the sprite
00249         //
00250         // optimized out:
00251         //
00252         //              geXForm3d_SetFromLeftUpIn(&RotationXForm, &Left, &Up, &In);
00253         //              FaceCameraXForm.Translation = S->Transform.Translation;
00254 
00255         // modify all the vertexes
00256         for (i = 0; i < SPRITE_NUM_CORNERS; i++)
00257         {
00258                 // optimized from:
00259                 //
00260                 //              S->Vertexes[i].X = S->Corners[i].X;
00261                 //              S->Vertexes[i].Y = S->Corners[i].Y;
00262                 //              S->Vertexes[i].Z = 0.0f;
00263                 //
00264                 //              geXForm3d_Transform(&FaceCameraXForm, &(S->Vertexes[i]), &(S->Vertexes[i]));
00265                 //
00266                 S->Vertexes[i].X = (S->Corners[i].X * Left.X) + (S->Corners[i].Y * Up.X) + S->Transform.Translation.X;
00267                 S->Vertexes[i].Y = (S->Corners[i].X * Left.Y) + (S->Corners[i].Y * Up.Y) + S->Transform.Translation.Y;
00268                 S->Vertexes[i].Z = (S->Corners[i].X * Left.Z) + (S->Corners[i].Y * Up.Z) + S->Transform.Translation.Z;
00269         }
00270 }
00271 
00272 
00273 __inline static void geSprite_UpdateSurfaceNormal(geSprite *S)
00274 {
00275         if (S->InternalTransformUsed)
00276         {
00277                 // rotate the surface normal by the internal transform
00278                 //
00279                 // optimized from:
00280                 //
00281                 //              S->SurfaceNormal.X = 0.0f;
00282                 //              S->SurfaceNormal.Y = 0.0f;
00283                 //              S->SurfaceNormal.Z = -1.0f;
00284                 // 
00285                 //              geXForm3d_Rotate(&(S->InternalTransform), &(S->SurfaceNormal), &(S->SurfaceNormal));
00286                 //
00287                 S->SurfaceNormal.X = -S->InternalTransform.AZ;
00288                 S->SurfaceNormal.Y = -S->InternalTransform.BZ;
00289                 S->SurfaceNormal.Z = -S->InternalTransform.CZ;
00290 
00291                 // rotate the surface normal by the external transform
00292                 geXForm3d_Rotate(&(S->Transform), &(S->SurfaceNormal), &(S->SurfaceNormal));
00293 
00294         }
00295 
00296         else
00297         {
00298                 // rotate the surface normal by the external transform
00299                 //
00300                 // optimized from:
00301                 //
00302                 //              S->SurfaceNormal.X = 0.0f;
00303                 //              S->SurfaceNormal.Y = 0.0f;
00304                 //              S->SurfaceNormal.Z = -1.0f;
00305                 // 
00306                 //              geXForm3d_Rotate(&(S->Transform), &(S->SurfaceNormal), &(S->SurfaceNormal));
00307                 //
00308                 S->SurfaceNormal.X = -S->Transform.AZ;
00309                 S->SurfaceNormal.Y = -S->Transform.BZ;
00310                 S->SurfaceNormal.Z = -S->Transform.CZ;
00311         }
00312 }
00313 
00314 
00315 __inline static void geSprite_UpdateSurfaceNormalToFaceCamera(geSprite *S, geCamera *Camera)
00316 {
00317         // get the camera's transform
00318         const geXForm3d *CameraXForm;
00319         CameraXForm = geCamera_GetWorldSpaceXForm(Camera);
00320 
00321         // get the vector opposite to the direction the camera is looking
00322         //
00323         // optimized from:
00324         //
00325         //              geXForm3d_GetIn(CameraXForm, &(S->SurfaceNormal));
00326         //              S->SurfaceNormal.X = -S->SurfaceNormal.X;
00327         //              S->SurfaceNormal.Y = -S->SurfaceNormal.Y;
00328         //              S->SurfaceNormal.Z = -S->SurfaceNormal.Z;
00329         //
00330         S->SurfaceNormal.X = CameraXForm->AZ;
00331         S->SurfaceNormal.Y = CameraXForm->BZ;
00332         S->SurfaceNormal.Z = CameraXForm->CZ;
00333 }
00334 
00335 
00336 __inline static void geSprite_CreateFrustumClippedScreenPoly(geSprite *S, geCamera *Camera, Frustum_Info *FInfo, geBoolean *Render, geBoolean *RenderBackface)
00337 {
00338         int i;
00339 
00340         const geXForm3d *CameraXForm;
00341 
00342         GFX_Plane *FPlanes;
00343 
00344         geVec3d *pVerts1;
00345         geVec3d *pVerts2;
00346         Surf_TexVert *pTexs1;
00347         Surf_TexVert *pTexs2;
00348         int32 Length;
00349 
00350         geVec3d CameraNormal;
00351 
00352         // if the face is always facing the camera, the backface will not
00353         // be rendered
00354         if (S->AlwaysFaceCamera)
00355         {
00356                 *RenderBackface = GE_FALSE;
00357         }
00358 
00359         // if the sprite is not always facing the camera, figure out which
00360         // face is facing the camera
00361         else
00362         {
00363                 // get the camera's transform
00364                 CameraXForm = geCamera_GetWorldSpaceXForm(Camera);
00365 
00366                 // get the direction vector from the camera to the sprite
00367                 geVec3d_Subtract(&(S->Position), &(CameraXForm->Translation), &CameraNormal);
00368                 geVec3d_Normalize(&CameraNormal);
00369 
00370                 // check to see how similar the sprite's surface normal is to the direction
00371                 // between the camera and the sprite, and determine if the backface is being
00372                 // shown to the camera
00373                 *RenderBackface = (geVec3d_DotProduct(&CameraNormal, &(S->SurfaceNormal)) > 0);
00374 
00375                 // if the backface is facing the camera, and it is disabled, then
00376                 // don't render it
00377                 if ( (*RenderBackface) && (!S->BackfaceEnabled) )
00378                 {
00379                         *Render = GE_FALSE;
00380                         return;
00381                 }
00382         }
00383 
00384         // no sense in rendering a completely transparent face
00385         if ( ((!(*RenderBackface)) && (S->RGBA.a == 0.0f)) || 
00386                          ((*RenderBackface) && (S->BackfaceRGBA.a == 0.0f)) )
00387         {
00388                 *Render = GE_FALSE;
00389                 return;
00390         }
00391 
00392         // copy the correct texture mappings
00393         if (*RenderBackface)
00394         {
00395                 for (i = 0; i < SPRITE_NUM_CORNERS; i++)
00396                 {
00397                         UnclippedUVRGBA[i].u = S->BackfaceUVs[i].u;
00398                         UnclippedUVRGBA[i].v = S->BackfaceUVs[i].v;
00399                 }
00400         }
00401         else
00402         {
00403                 for (i = 0; i < SPRITE_NUM_CORNERS; i++)
00404                 {
00405                         UnclippedUVRGBA[i].u = S->UVs[i].u;
00406                         UnclippedUVRGBA[i].v = S->UVs[i].v;
00407                 }
00408         }
00409 
00410         // initialize pointers for frustum clipping
00411         FPlanes = FInfo->Planes;
00412         pVerts1 = S->Vertexes;
00413         pTexs1 = UnclippedUVRGBA;
00414         pVerts2 = FrustumClippedVertexes1;
00415         pTexs2 = FrustumClippedUVRGBA1;
00416         Length = SPRITE_NUM_CORNERS;
00417 
00418         // clip the vertexes (including their texture and lighting) to the frustum
00419         for (i = 0; i < FInfo->NumPlanes; i++, FPlanes++)
00420         {
00421                 
00422                 if (!Frustum_ClipToPlaneUV(FPlanes, pVerts1, pVerts2, pTexs1, pTexs2, Length, &FrustumNumClippedTexturedLitVertices))
00423                         break;
00424 
00425                 assert(FrustumNumClippedTexturedLitVertices < MAX_TEMP_VERTS);
00426                 
00427                 // this is hard to read, but essentially what is happening is that
00428                 // source data is swapping with destination data every frustum clip.
00429                 // in this way, vertexes are further clipped each time
00430                 if (pVerts2 == FrustumClippedVertexes1)
00431                 {
00432                         pVerts1 = FrustumClippedVertexes1;
00433                         pVerts2 = FrustumClippedVertexes2;
00434                         pTexs1 = FrustumClippedUVRGBA1;
00435                         pTexs2 = FrustumClippedUVRGBA2;
00436                 }
00437                 else
00438                 {
00439                         pVerts1 = FrustumClippedVertexes2;
00440                         pVerts2 = FrustumClippedVertexes1;
00441                         pTexs1 = FrustumClippedUVRGBA2;
00442                         pTexs2 = FrustumClippedUVRGBA1;
00443                 }
00444 
00445                 Length = FrustumNumClippedTexturedLitVertices;
00446         }
00447                         
00448         assert(FrustumNumClippedTexturedLitVertices < MAX_TEMP_VERTS);
00449 
00450         // Not visible or not enough vertexes
00451         if ( (i != FInfo->NumPlanes) || (FrustumNumClippedTexturedLitVertices < 3) )
00452         {
00453                 *Render = GE_FALSE;
00454                 return;
00455         }
00456 
00457         // Transform the face to camera space
00458         geCamera_TransformArray(Camera, pVerts1, pVerts1, FrustumNumClippedTexturedLitVertices);
00459 
00460         // Project the face, and combine vertex and texture and lighting data into one structure
00461         Frustum_ProjectRGBA(pVerts1, pTexs1, (DRV_TLVertex*)&FrustumClippedTexturedLitVertexes, FrustumNumClippedTexturedLitVertices, Camera);
00462 
00463         *Render = GE_TRUE;
00464 }
00465 
00466 
00467 __inline static void geSprite_UpdateBackfaceTextureMap(geSprite *S)
00468 {
00469         if (S->BackfaceMirrorImage)
00470         {
00471                 S->BackfaceUVs[0].u = S->UVs[0].u;
00472                 S->BackfaceUVs[0].v = S->UVs[0].v;
00473                 S->BackfaceUVs[1].u = S->UVs[1].u;
00474                 S->BackfaceUVs[1].v = S->UVs[1].v;
00475                 S->BackfaceUVs[2].u = S->UVs[2].u;
00476                 S->BackfaceUVs[2].v = S->UVs[2].v;
00477                 S->BackfaceUVs[3].u = S->UVs[3].u;
00478                 S->BackfaceUVs[3].v = S->UVs[3].v;
00479         }
00480         else
00481         {
00482                 S->BackfaceUVs[0].u = S->UVs[1].u;
00483                 S->BackfaceUVs[0].v = S->UVs[1].v;
00484                 S->BackfaceUVs[1].u = S->UVs[0].u;
00485                 S->BackfaceUVs[1].v = S->UVs[0].v;
00486                 S->BackfaceUVs[2].u = S->UVs[3].u;
00487                 S->BackfaceUVs[2].v = S->UVs[3].v;
00488                 S->BackfaceUVs[3].u = S->UVs[2].u;
00489                 S->BackfaceUVs[3].v = S->UVs[2].v;
00490         }
00491 }
00492 
00493 
00494 __inline static void geSprite_UpdateTextureMap(geSprite *S)
00495 {
00496 /*
00497         S->UVs[0].u = TextureOffsetX;
00498         S->UVs[0].v = 1 - TextureOffsetY;
00499 
00500         S->UVs[1].u = TextureOffsetX + TextureScaleX;
00501         S->UVs[1].v = 1 - TextureOffsetY;
00502 
00503         S->UVs[2].u = TextureOffsetX + TextureScaleX;
00504         S->UVs[2].v = 1 - TextureOffsetY - TextureScaleY;
00505 
00506         S->UVs[3].u = TextureOffsetX;
00507         S->UVs[3].v = 1 - TextureOffsetY - TextureScaleY;
00508 */
00509         // optimized (compiler probably would figure it out, but why take the chance)
00510         S->UVs[3].u = S->UVs[0].u = S->TextureOffsetX;
00511         S->UVs[1].v = S->UVs[0].v = 1 - S->TextureOffsetY;
00512 
00513         S->UVs[2].u = S->UVs[1].u = S->TextureOffsetX + S->TextureScaleX;
00514         S->UVs[1].v = 1 - S->TextureOffsetY;
00515 
00516         S->UVs[3].v = S->UVs[2].v = 1 - S->TextureOffsetY - S->TextureScaleY;
00517 
00518         geSprite_UpdateBackfaceTextureMap(S);
00519 }
00520 
00521 
00522 #pragma warning(disable : 4700 )
00523 __inline static void geSprite_UpdateLighting(geSprite *S, geWorld *World)
00524 {
00525         int32 i, j;
00526 
00527         geFloat Intensity;
00528 
00529         geBoolean DoBackface;
00530 
00531         geSprite_DynamicLight TempSwap;
00532 
00533         geFloat Scale;
00534 
00535         geVec3d PositionBelowFloor;
00536 
00537         geBoolean       InsideWorldModel;
00538         geBoolean       FloorBeneath;
00539 
00540         geVec3d Impact;
00541         int32           Node;
00542         int32           Plane;
00543 
00544         GFX_Node                        *GFXNodes;
00545         Surf_SurfInfo   *Surf;
00546         GE_RGBA                         FaceLightmapColor;
00547 
00548 
00549         // first apply the ambient light
00550         S->RGBA.r = S->AmbientLight.r;
00551         S->RGBA.g = S->AmbientLight.g;
00552         S->RGBA.b = S->AmbientLight.b;
00553 
00554         // apply the ambient to the backface, if there is one
00555         DoBackface = ( (S->BackfaceEnabled) && !(S->AlwaysFaceCamera) );
00556         if (DoBackface)
00557         {
00558                 S->BackfaceRGBA.r = S->AmbientLight.r;
00559                 S->BackfaceRGBA.g = S->AmbientLight.g;
00560                 S->BackfaceRGBA.b = S->AmbientLight.b;
00561         }
00562 
00563         // calculate the fill light, if it applies
00564         if (S->UseFillLight)
00565         {
00566                 Intensity = geVec3d_DotProduct( &(S->FillLightNormal), &(S->SurfaceNormal) );
00567 
00568                 if (Intensity < 0.0f)
00569                 {
00570                         S->RGBA.r -= (Intensity * S->FillLight.r);
00571                         S->RGBA.g -= (Intensity * S->FillLight.g);
00572                         S->RGBA.b -= (Intensity * S->FillLight.b);
00573                 }
00574                 else
00575                 {
00576                         // apply the fill light to the backface, if there is one
00577                         if (DoBackface)
00578                         {
00579                                 S->BackfaceRGBA.r += (Intensity * S->FillLight.r);
00580                                 S->BackfaceRGBA.g += (Intensity * S->FillLight.g);
00581                                 S->BackfaceRGBA.b += (Intensity * S->FillLight.b);
00582                         }
00583                 }
00584         }
00585 
00586         if (S->MaximumDynamicLightsToUse > 0)
00587         {
00588                 // a pointer to make things easier
00589                 Light_DLight *DynamicLights = World->LightInfo->DynamicLights;
00590                 
00591                 // start out with no dynamic lights available for lighting
00592                 int32 DLCount = 0;
00593 
00594                 // get all the dynamic lights that are active
00595                 for (i = 0; i < MAX_DYNAMIC_LIGHTS; i++)
00596                 {
00597                         if (DynamicLights[i].Active)
00598                         {
00599                                 // the normal is a vector distance
00600                                 geVec3d Normal;
00601                                 geVec3d_Subtract(&(S->Position), &(DynamicLights[i].Pos), &Normal);
00602 
00603                                 // which is why it can be used to calculate distance (squared)
00604                                 geSpriteDynamicLights[DLCount].Distance = (Normal.X * Normal.X) + 
00605                                                                                                                                                                                                         (Normal.Y * Normal.Y) + 
00606                                                                                                                                                                                                         (Normal.Z * Normal.Z);
00607 
00608                                 // if the sprite is inside the active dynamic light's radius, then add it to the array
00609                                 if (geSpriteDynamicLights[DLCount].Distance < (DynamicLights[i].Radius * DynamicLights[i].Radius))
00610                                 {
00611                                         geSpriteDynamicLights[DLCount].Color.r = DynamicLights[i].Color.r;
00612                                         geSpriteDynamicLights[DLCount].Color.g = DynamicLights[i].Color.g;
00613                                         geSpriteDynamicLights[DLCount].Color.b = DynamicLights[i].Color.b;
00614                                         geSpriteDynamicLights[DLCount].Radius = DynamicLights[i].Radius;
00615                                         // this normal will be normalized later
00616                                         geSpriteDynamicLights[DLCount].Normal = Normal;
00617                                         DLCount++;
00618                                 }
00619                         }
00620                 }
00621 
00622                 // try to eliminate some easy out possibilities
00623                 if (DLCount > 1)
00624                 {
00625                         // if there is only one light needed, just make sure the closest
00626                         // is in the first location
00627                         if ( (S->MaximumDynamicLightsToUse == 1) )
00628                         {
00629                                 for (i = 1; i < DLCount; i++)
00630                                 {
00631                                         if (geSpriteDynamicLights[i].Distance < geSpriteDynamicLights[0].Distance)
00632                                                 geSpriteDynamicLights[0] = geSpriteDynamicLights[i];
00633                                 }
00634                         }
00635                         // if there is not just one light to get out of the array, then
00636                         // sort the active dynamic lights by distance (squared)
00637                         else
00638                         {
00639                                 for (i = 0; i < DLCount; i++)
00640                                 {
00641                                         for (j = 0; j < (DLCount - 1); j++)
00642                                         {
00643                                                 if (geSpriteDynamicLights[j].Distance > geSpriteDynamicLights[j+1].Distance)
00644                                                 {
00645                                                         TempSwap = geSpriteDynamicLights[j];
00646                                                         geSpriteDynamicLights[j] = geSpriteDynamicLights[j+1];
00647                                                         geSpriteDynamicLights[j+1] = TempSwap;
00648                                                 }
00649                                         }
00650                                 }
00651                         }
00652                 }
00653 
00654                 // use whatever dynamic lights are available, under the maximum number
00655                 if (DLCount > S->MaximumDynamicLightsToUse)
00656                         DLCount = S->MaximumDynamicLightsToUse;
00657 
00658                 // calculate the effect the closest lights have on the face
00659                 for (i = 0; i < DLCount; i++)
00660                 {
00661                         // makes the code more readable
00662                         geVec3d *LightNormal = &(geSpriteDynamicLights[i].Normal);
00663 
00664                         // get the real distance (not the distance squared)
00665                         geFloat Distance = (geFloat)sqrt(geSpriteDynamicLights[i].Distance);
00666 
00667                         // see, I told you it would get normalized (although not perfectly)
00668                         if (Distance > 1.0f)
00669                                 geVec3d_Scale(LightNormal, (1.0f / Distance), LightNormal);
00670                         else
00671                                 Distance = 1.0f;
00672 
00673                         Scale = 1.0f - (Distance / geSpriteDynamicLights[i].Radius);
00674 
00675                         Intensity       =       geVec3d_DotProduct( LightNormal, &(S->SurfaceNormal) );
00676 
00677                         if (Intensity < 0.0f)
00678                         {
00679                                 S->RGBA.r -= (Intensity * geSpriteDynamicLights[i].Color.r * Scale);
00680                                 S->RGBA.g -= (Intensity * geSpriteDynamicLights[i].Color.g * Scale);
00681                                 S->RGBA.b -= (Intensity * geSpriteDynamicLights[i].Color.b * Scale);
00682                         }
00683                         else
00684                         {
00685                                 if (DoBackface)
00686                                 {
00687                                         S->BackfaceRGBA.r += (Intensity * geSpriteDynamicLights[i].Color.r * Scale);
00688                                         S->BackfaceRGBA.g += (Intensity * geSpriteDynamicLights[i].Color.g * Scale);
00689                                         S->BackfaceRGBA.b += (Intensity * geSpriteDynamicLights[i].Color.b * Scale);
00690                                 }
00691                         }
00692                 }
00693         }
00694 
00695         if (S->UseLightFromFloor)
00696         {
00697                 PositionBelowFloor.X = S->Position.X;
00698                 PositionBelowFloor.Y = S->Position.Y - BIG_DISTANCE;
00699                 PositionBelowFloor.Z = S->Position.Z;
00700 
00701                 // Get shadow hit plane impact point
00702                 InsideWorldModel = Trace_WorldCollisionExact2(World, &(S->Position), &(S->Position), &Impact, &Node, &Plane, NULL);
00703                 FloorBeneath = Trace_WorldCollisionExact2(World, &(S->Position), &PositionBelowFloor, &Impact, &Node, &Plane, NULL);
00704 
00705                 // Now find the color of the mesh by getting the lightmap point he is standing on...
00706                 if ( (!InsideWorldModel) && FloorBeneath)
00707                 {
00708                         // make things a bit more readable
00709                         GFXNodes = World->CurrentBSP->BSPData.GFXNodes;
00710 
00711                         // get the surface infomation for the node below the sprite
00712                         Surf = &(World->CurrentBSP->SurfInfo[GFXNodes[Node].FirstFace]);
00713 
00714                         // if there are lightmap faces, then find the light mapped face below the sprite
00715                         if (Surf->LInfo.Face >= 0)
00716                         {
00717                                 // go through each face looking for one below the sprite
00718                                 for (i = 0; i < GFXNodes[Node].NumFaces; i++)
00719                                 {
00720                                         // if the surface is located at the point below the sprite,
00721                                         // get the lightmap
00722                                         if (Surf_InSurfBoundingBox(Surf, &Impact, 20.0f))
00723                                         {
00724                                                 // setup the lightmap for the surface
00725                                                 Light_SetupLightmap(&Surf->LInfo, NULL);
00726 
00727                                                 // get the lightmap color at the point and add it to the
00728                                                 // light of the sprite, and stop looking for any more light
00729                                                 if (Light_GetLightmapRGB(Surf, &Impact, &FaceLightmapColor))
00730                                                 {
00731                                                         S->RGBA.r += FaceLightmapColor.r;
00732                                                         S->RGBA.g += FaceLightmapColor.g;
00733                                                         S->RGBA.b += FaceLightmapColor.b;
00734 
00735                                                         if (DoBackface)
00736                                                         {
00737                                                                 S->BackfaceRGBA.r += FaceLightmapColor.r;
00738                                                                 S->BackfaceRGBA.g += FaceLightmapColor.g;
00739                                                                 S->BackfaceRGBA.b += FaceLightmapColor.b;
00740                                                         }
00741 
00742                                                         break;
00743                                                 }
00744                                         }
00745                                         
00746                                         // go to the next surface
00747                                         Surf++;
00748                                 }
00749                         }
00750                 }
00751         }
00752 
00753         // fix up any over or under flow
00754         if (S->RGBA.r > 255.0f)
00755                 S->RGBA.r = 255.0f;
00756         else if (S->RGBA.r < 0.0f)
00757                 S->RGBA.r = 0.0f;
00758 
00759         if (S->RGBA.g > 255.0f)
00760                 S->RGBA.g = 255.0f;
00761         else if (S->RGBA.g < 0.0f)
00762                 S->RGBA.g = 0.0f;
00763 
00764         if (S->RGBA.b > 255.0f)
00765                 S->RGBA.b = 255.0f;
00766         else if (S->RGBA.b < 0.0f)
00767                 S->RGBA.b = 0.0f;
00768 
00769         if (DoBackface)
00770         {
00771                 // fix up any over or under flow
00772                 if (S->BackfaceRGBA.r > 255.0f)
00773                         S->BackfaceRGBA.r = 255.0f;
00774                 else if (S->BackfaceRGBA.r < 0.0f)
00775                         S->BackfaceRGBA.r = 0.0f;
00776 
00777                 if (S->BackfaceRGBA.g > 255.0f)
00778                         S->BackfaceRGBA.g = 255.0f;
00779                 else if (S->BackfaceRGBA.g < 0.0f)
00780                         S->BackfaceRGBA.g = 0.0f;
00781 
00782                 if (S->BackfaceRGBA.b > 255.0f)
00783                         S->BackfaceRGBA.b = 255.0f;
00784                 else if (S->BackfaceRGBA.b < 0.0f)
00785                         S->BackfaceRGBA.b = 0.0f;
00786         }
00787 }
00788 #pragma warning(default : 4700 )
00789 
00790 
00791 GENESISAPI int32 GENESISCC geSprite_GetCount()
00792 {
00793         return geSprite_Count;
00794 }
00795 
00796 
00797 GENESISAPI geSprite *GENESISCC geSprite_Create(geBitmap *SpriteBitmap, geBitmap *SpriteBackfaceBitmap)
00798 {
00799         geSprite *S;
00800 
00801         if (SpriteBitmap)
00802         {
00803                 if ( geBitmap_IsValid(SpriteBitmap) == GE_FALSE )
00804                 {
00805                         geErrorLog_Add( ERR_SPRITE_INVALIDBITMAP , NULL);
00806                         return NULL;
00807                 }
00808         }
00809 
00810         if ( (SpriteBackfaceBitmap) && (SpriteBackfaceBitmap != SpriteBitmap) )
00811         {
00812                 if ( geBitmap_IsValid(SpriteBackfaceBitmap) == GE_FALSE )
00813                 {
00814                         geErrorLog_Add( ERR_SPRITE_INVALIDBITMAP , NULL);
00815                         return NULL;
00816                 }
00817         }
00818 
00819 
00820         S = GE_RAM_ALLOCATE_STRUCT( geSprite );
00821         if ( S == NULL )
00822         {
00823                 geErrorLog_Add( ERR_SPRITE_ENOMEM , NULL);
00824                 return NULL;
00825         }
00826         
00827         S->RefCount = 0;
00828 
00829         S->Bitmap = SpriteBitmap;
00830         if (SpriteBitmap)
00831                 geBitmap_CreateRef(SpriteBitmap);
00832 
00833         S->BackfaceBitmap = SpriteBackfaceBitmap;
00834         if ( (SpriteBackfaceBitmap) && (SpriteBitmap != SpriteBackfaceBitmap) )
00835                 geBitmap_CreateRef(SpriteBackfaceBitmap);
00836 
00837         S->BackfaceEnabled = GE_TRUE;
00838         S->BackfaceMirrorImage = GE_TRUE;
00839 
00840         S->AlwaysFaceCamera = GE_FALSE;
00841         
00842         geXForm3d_SetIdentity(&(S->Transform));
00843 
00844         S->InternalTransformUsed = GE_FALSE;
00845         geXForm3d_SetIdentity(&(S->InternalTransform));
00846 
00847         geSprite_UpdatePosition(S);
00848 
00849         S->ScaleX = 1.0f;
00850         S->ScaleY = 1.0f;
00851         geSprite_UpdateCorners(S);
00852 
00853         S->TextureOffsetX = 0.0f;
00854         S->TextureOffsetY = 0.0f;
00855         S->TextureScaleX = 1.0f;
00856         S->TextureScaleY = 1.0f;
00857         geSprite_UpdateTextureMap(S);
00858 
00859         geVec3d_Clear(&(S->BoundingBoxMinCorner));
00860         geVec3d_Clear(&(S->BoundingBoxMaxCorner));
00861 
00862         S->AmbientLight.r = 0.1f;               
00863         S->AmbientLight.g = 0.1f;                       
00864         S->AmbientLight.b = 0.1f;
00865         S->UseFillLight = GE_FALSE;
00866         S->UseLightFromFloor = GE_FALSE;
00867         S->MaximumDynamicLightsToUse = 0;
00868 
00869         S->LightingUsesSurfaceNormal = GE_FALSE;
00870 
00871         S->RGBA.a = 255.0f;
00872         S->BackfaceRGBA.a = 255.0f;
00873 
00874         S->UserData = NULL;
00875 
00876         S->TransformChanged = GE_TRUE;
00877         S->LightingChanged = GE_TRUE;
00878 
00879         assert( geSprite_IsValid(S) );
00880 
00881         geSprite_Count++;
00882 
00883         return S;
00884 }       
00885 
00886 
00887 GENESISAPI void GENESISCC geSprite_CreateRef(geSprite *S)
00888 {
00889         assert( geSprite_IsValid(S) );
00890 
00891         S->RefCount++;
00892         geSprite_RefCount++;
00893 }
00894 
00895 
00896 GENESISAPI void GENESISCC geSprite_Destroy(geSprite **pS)
00897 {
00898         geSprite *S;
00899         assert(  pS != NULL );
00900         assert( *pS != NULL );
00901         assert( geSprite_IsValid(*pS) );
00902         
00903         S = *pS;
00904         if (S->RefCount > 0)
00905         {
00906                 S->RefCount --;
00907                 geSprite_RefCount--;
00908                 return;
00909         }
00910 
00911         if (S->Bitmap)
00912         {
00913                 geBitmap_Destroy(&(S->Bitmap));
00914         }
00915 
00916         if ( (S->BackfaceBitmap) && (S->BackfaceBitmap != S->Bitmap) )
00917         {
00918                 geBitmap_Destroy(&(S->BackfaceBitmap));
00919         }
00920 
00921         geRam_Free(*pS);
00922         geSprite_Count--;
00923         *pS = NULL;
00924 }
00925 
00926 
00927 GENESISAPI geBoolean GENESISCC geSprite_IsValid(const geSprite *S)
00928 {
00929         if (S == NULL)
00930                 return GE_FALSE;
00931 
00932         return GE_TRUE;
00933 }
00934 
00935 
00936 GENESISAPI geBitmap *GENESISCC geSprite_GetBitmap(const geSprite *S)
00937 {
00938         assert ( (S->Bitmap == NULL) || (geBitmap_IsValid(S->Bitmap)) );
00939 
00940         return S->Bitmap;
00941 }
00942 
00943 
00944 GENESISAPI geBitmap *GENESISCC geSprite_GetBackfaceBitmap(const geSprite *S)
00945 {
00946         assert ( (S->BackfaceBitmap == NULL) || (geBitmap_IsValid(S->BackfaceBitmap)) );
00947 
00948         return S->BackfaceBitmap;
00949 }
00950 
00951 
00952 GENESISAPI void GENESISCC geSprite_GetBackface(const geSprite *S, geBoolean *Enabled, geBoolean *MirrorImage)
00953 {
00954         assert ( Enabled );
00955         assert ( MirrorImage );
00956 
00957         *Enabled = S->BackfaceEnabled;
00958         *MirrorImage = S->BackfaceMirrorImage;
00959 }
00960 
00961 
00962 GENESISAPI void GENESISCC geSprite_SetBackface(geSprite *S, const geBoolean Enabled, const geBoolean MirrorImage)
00963 {
00964         assert( geSprite_IsValid(S) );
00965 
00966         // because lighting the backface requires a lot of extra calculations, the
00967         // backface doesn't have correct lighting if it has been turned off. so, if it
00968         // is turned on, lighting needs to be updated
00969         S->LightingChanged = (S->LightingChanged || ((Enabled) && (!S->BackfaceEnabled)) );
00970 
00971         // if the mirror imaging is changed, then update the texture map for the backface
00972         if (S->BackfaceMirrorImage != MirrorImage)
00973         {
00974                 S->BackfaceMirrorImage = MirrorImage;
00975                 geSprite_UpdateBackfaceTextureMap(S);
00976         }
00977 
00978         S->BackfaceEnabled = Enabled;
00979 }
00980 
00981 
00982 GENESISAPI void GENESISCC geSprite_GetFaceCamera(const geSprite *S, geBoolean *Enabled)
00983 {
00984         assert( geSprite_IsValid(S) );
00985         assert( Enabled != NULL );
00986 
00987         *Enabled = S->AlwaysFaceCamera;
00988 }
00989 
00990 
00991 GENESISAPI void GENESISCC geSprite_SetFaceCamera(geSprite *S, geBoolean Enabled)
00992 {
00993         assert( geSprite_IsValid(S) );
00994 
00995         // if facing the camera is being disabled, then force an
00996         // update on everything the transform affects
00997         if ( (S->AlwaysFaceCamera) && (!Enabled) )
00998         {
00999                 S->TransformChanged = GE_TRUE;
01000         }
01001 
01002         S->AlwaysFaceCamera = Enabled;
01003 
01004         geSprite_UpdatePosition(S);
01005 }
01006 
01007 
01008 GENESISAPI void GENESISCC geSprite_GetPosition(const geSprite *S, geVec3d *Pos)
01009 {
01010         assert( geSprite_IsValid(S) );
01011         assert( Pos != NULL );
01012         assert( geXForm3d_IsOrthonormal(&(S->Transform)) );
01013 
01014         *Pos = S->Transform.Translation;
01015 }
01016 
01017 
01018 GENESISAPI void GENESISCC geSprite_SetPosition(geSprite *S, const geVec3d *Pos)
01019 {
01020         assert( geSprite_IsValid(S) );
01021         assert( Pos != NULL );
01022         assert( geXForm3d_IsOrthonormal(&(S->Transform)) );
01023 
01024         S->Transform.Translation = *Pos;
01025 
01026         geSprite_UpdatePosition(S);
01027 
01028         S->TransformChanged = GE_TRUE;
01029 }
01030 
01031 
01032 GENESISAPI void GENESISCC geSprite_GetTransform(const geSprite *S, geXForm3d *Transform)
01033 {
01034         assert( geSprite_IsValid(S) );
01035         assert( Transform!= NULL );
01036 
01037         *Transform = S->Transform;
01038 }
01039 
01040 
01041 GENESISAPI void GENESISCC geSprite_SetTransform(geSprite *S, const geXForm3d *Transform)
01042 {
01043         assert( geSprite_IsValid(S) );
01044         assert( Transform );
01045 
01046         S->Transform = *Transform;
01047         
01048         geSprite_UpdatePosition(S);
01049 
01050         S->TransformChanged = GE_TRUE;
01051 }
01052 
01053 
01054 GENESISAPI void GENESISCC geSprite_GetInternalTransform(const geSprite *S, geXForm3d *Transform)
01055 {
01056         assert( geSprite_IsValid(S) );
01057         assert( Transform );
01058 
01059         *Transform = S->InternalTransform;
01060 }
01061 
01062 
01063 GENESISAPI void GENESISCC geSprite_SetInternalTransform(geSprite *S, const geXForm3d *Transform)
01064 {
01065         assert( geSprite_IsValid(S) );
01066         assert( Transform );
01067 
01068         S->InternalTransform = *Transform;
01069         S->InternalTransformUsed = !( geXForm3d_IsIdentity(Transform) );
01070 
01071         geSprite_UpdatePosition(S);
01072 
01073         S->TransformChanged = GE_TRUE;
01074 }
01075 
01076 
01077 GENESISAPI void GENESISCC geSprite_GetScale(const geSprite *S, geFloat *ScaleX, geFloat *ScaleY)
01078 {
01079         assert( geSprite_IsValid(S)!=GE_FALSE );
01080 
01081         *ScaleX = S->ScaleX;
01082         *ScaleY = S->ScaleY;
01083 }
01084 
01085 
01086 GENESISAPI void GENESISCC geSprite_SetScale(geSprite *S, geFloat ScaleX, geFloat ScaleY)
01087 {
01088         assert( geSprite_IsValid(S)!=GE_FALSE );
01089 
01090         if ( (S->ScaleX != ScaleX) || (S->ScaleY != ScaleY) )
01091         {
01092                 S->ScaleX = ScaleX;
01093                 S->ScaleY = ScaleY;
01094 
01095                 geSprite_UpdateCorners(S);
01096 
01097                 S->TransformChanged = GE_TRUE;
01098         }
01099 }
01100 
01101 
01102 GENESISAPI void GENESISCC geSprite_GetExtBox(const geSprite *S, geExtBox *ExtBox)
01103 {
01104         assert( geSprite_IsValid(S) );
01105         assert( ExtBox != NULL );
01106         assert( geXForm3d_IsOrthonormal(&(S->Transform)) );
01107 
01108         geVec3d_Add( &(S->Transform.Translation), &(S->BoundingBoxMinCorner), &(ExtBox->Min));
01109         geVec3d_Add( &(S->Transform.Translation), &(S->BoundingBoxMaxCorner), &(ExtBox->Max));
01110 }
01111 
01112 
01113 GENESISAPI void GENESISCC geSprite_GetNonWorldExtBox(const geSprite *S, geExtBox *ExtBox)
01114 {
01115         assert( geSprite_IsValid(S) );
01116         assert( ExtBox != NULL );
01117         
01118         ExtBox->Min = S->BoundingBoxMinCorner;
01119         ExtBox->Max = S->BoundingBoxMaxCorner;
01120 }
01121 
01122 
01123 GENESISAPI void GENESISCC geSprite_SetExtBox(geSprite *S, const geExtBox *ExtBox)
01124 {
01125         assert( geSprite_IsValid(S) );
01126         assert( geExtBox_IsValid(ExtBox) );
01127 
01128         S->BoundingBoxMinCorner = ExtBox->Min;
01129         S->BoundingBoxMaxCorner = ExtBox->Max;
01130 }
01131 
01132 
01133 GENESISAPI void GENESISCC geSprite_GetTextureParameters(const geSprite *S,
01134         geFloat *OffsetX,
01135         geFloat *OffsetY,
01136         geFloat *ScaleX,
01137         geFloat *ScaleY)
01138 {
01139         assert( geSprite_IsValid(S) );
01140         assert( OffsetX != NULL );
01141         assert( OffsetY != NULL );
01142         assert( ScaleX != NULL );
01143         assert( ScaleY != NULL );
01144 
01145         *OffsetX = S->TextureOffsetX;
01146         *OffsetY = S->TextureOffsetY;
01147         *ScaleX = S->TextureScaleX;
01148         *ScaleY = S->TextureScaleY;
01149 }
01150 
01151 
01152 GENESISAPI void GENESISCC geSprite_SetTextureParameters(geSprite *S,
01153         geFloat OffsetX,
01154         geFloat OffsetY,
01155         geFloat ScaleX,
01156         geFloat ScaleY)
01157 {
01158         assert( geSprite_IsValid(S) );
01159 
01160         S->TextureOffsetX = OffsetX;
01161         S->TextureOffsetY = OffsetY;
01162         S->TextureScaleX = ScaleX;
01163         S->TextureScaleY = ScaleY;
01164 
01165         geSprite_UpdateTextureMap(S);
01166 }
01167 
01168 
01169 GENESISAPI void GENESISCC geSprite_GetLightingOptions(const geSprite *S,
01170         geFloat *AmbientLightRed,                       
01171         geFloat *AmbientLightGreen,                     
01172         geFloat *AmbientLightBlue,                      
01173         geBoolean *UseFillLight,
01174         geVec3d *FillLightNormal,
01175         geFloat *FillLightRed,                          
01176         geFloat *FillLightGreen,                                
01177         geFloat *FillLightBlue,                         
01178         geBoolean *UseLightFromFloor,
01179         int32 *MaximumDynamicLightsToUse)
01180 {
01181         assert( geSprite_IsValid(S) );
01182 
01183         assert( AmbientLightRed != NULL );
01184         assert( AmbientLightGreen != NULL );                    
01185         assert( AmbientLightBlue != NULL );                     
01186         assert( UseFillLight != NULL );
01187         assert( FillLightNormal != NULL );
01188         assert( FillLightRed != NULL ); 
01189         assert( FillLightGreen != NULL );       
01190         assert( FillLightBlue != NULL );        
01191         assert( UseLightFromFloor != NULL );
01192         assert( MaximumDynamicLightsToUse != NULL );
01193 
01194         *AmbientLightRed = S->AmbientLight.r;
01195         *AmbientLightGreen = S->AmbientLight.g;
01196         *AmbientLightBlue = S->AmbientLight.b;
01197         *UseFillLight = S->UseFillLight;
01198         *FillLightNormal = S->FillLightNormal;
01199         *FillLightRed = S->FillLight.r;
01200         *FillLightGreen = S->FillLight.g;
01201         *FillLightBlue = S->FillLight.b;
01202         *UseLightFromFloor = S->UseLightFromFloor;
01203         *MaximumDynamicLightsToUse = S->MaximumDynamicLightsToUse;
01204 }
01205 
01206 
01207 GENESISAPI void GENESISCC geSprite_SetLightingOptions(geSprite *S,
01208         geFloat AmbientLightRed,                        // 0 .. 255
01209         geFloat AmbientLightGreen,              // 0 .. 255
01210         geFloat AmbientLightBlue,                       // 0 .. 255
01211         geBoolean UseFillLight,
01212         const geVec3d *FillLightNormal,
01213         geFloat FillLightRed,                                   // 0 .. 255
01214         geFloat FillLightGreen,                         // 0 .. 255
01215         geFloat FillLightBlue,                          // 0 .. 255
01216         geBoolean UseLightFromFloor,
01217         int32 MaximumDynamicLightsToUse // 0 for none
01218 )
01219 {
01220         assert( geSprite_IsValid(S) );
01221         assert( geVec3d_IsValid(FillLightNormal) );
01222 
01223         S->AmbientLight.r = AmbientLightRed;
01224         S->AmbientLight.g = AmbientLightGreen;
01225         S->AmbientLight.b = AmbientLightBlue;
01226         S->UseFillLight = UseFillLight;
01227         S->FillLightNormal = *FillLightNormal;
01228         S->FillLight.r = FillLightRed;
01229         S->FillLight.g = FillLightGreen;
01230         S->FillLight.b = FillLightBlue;
01231         S->UseLightFromFloor = UseLightFromFloor;
01232         S->MaximumDynamicLightsToUse = MaximumDynamicLightsToUse;
01233 
01234         // if fill light or dynamic lights are now used, and they weren't before,
01235         // then the surface normal will be needed.
01236         //
01237         // if the transform has changed, then it will be updated next render, so
01238         // don't do it now
01239         //
01240         // if the camera always faces the camera, then this will be updated every
01241         // render (and using a different normal), so don't do it now.
01242         if ( (!S->TransformChanged) && 
01243                          (!S->AlwaysFaceCamera) &&
01244                          (!S->LightingUsesSurfaceNormal) && ((UseFillLight) || (MaximumDynamicLightsToUse > 0)) )
01245                 geSprite_UpdateSurfaceNormal(S);
01246 
01247         // store whether vertexes are required for lighting (only for fill lights and dynamic lights)
01248         S->LightingUsesSurfaceNormal = (S->UseFillLight) || (S->MaximumDynamicLightsToUse > 0);
01249 }
01250 
01251 
01252 GENESISAPI void GENESISCC geSprite_GetAlpha(const geSprite *S, geFloat *Alpha, geFloat *BackfaceAlpha)
01253 {
01254         assert( geSprite_IsValid(S) );
01255         assert( Alpha );
01256         assert( BackfaceAlpha );
01257 
01258         *Alpha = S->RGBA.a;
01259         *BackfaceAlpha = S->BackfaceRGBA.a;
01260 }
01261 
01262 
01263 GENESISAPI void GENESISCC geSprite_SetAlpha(geSprite *S, geFloat Alpha, geFloat BackfaceAlpha)
01264 {
01265         assert( geSprite_IsValid(S) );
01266 
01267         S->RGBA.a = Alpha;
01268         S->BackfaceRGBA.a = BackfaceAlpha;
01269 
01270         // alphas cannot be less than 0 or greater than 255
01271         if (S->RGBA.a < 0)
01272                 S->RGBA.a = 0.0f;
01273         else if (S->RGBA.a > 255.0f)
01274                 S->RGBA.a = 255.0f;
01275         if (S->BackfaceRGBA.a < 0)
01276                 S->BackfaceRGBA.a = 0.0f;
01277         else if (S->BackfaceRGBA.a > 255.0f)
01278                 S->BackfaceRGBA.a = 255.0f;
01279 }
01280 
01281 
01282 GENESISAPI void *GENESISCC geSprite_GetUserData(const geSprite *S)
01283 {
01284         assert( geSprite_IsValid(S) );
01285 
01286         return S->UserData;
01287 }
01288 
01289 
01290 GENESISAPI void GENESISCC geSprite_SetUserData(geSprite *S, void *UserData)
01291 {
01292         assert( geSprite_IsValid(S) );
01293 
01294         S->UserData = UserData;
01295 }
01296 
01297 
01298 geBoolean GENESISCC geSprite_RenderPrep(geSprite *S, geWorld *World)
01299 {
01300         assert( geSprite_IsValid(S) );
01301 
01302         // if the sprite uses a front face bitmap, add the bitmap to the world
01303         if (S->Bitmap)
01304         {
01305                 if ( geWorld_AddBitmap(World, S->Bitmap) == GE_FALSE )
01306                 {
01307                         geErrorLog_AddString(-1, "Sprite_RenderPrep : World_AddBitmap", NULL);
01308                         return GE_FALSE;
01309                 }
01310         }
01311 
01312         // if the sprite uses a backface bitmap (and it is not the same as the front),
01313         // add the bitmap to the world
01314         if ( (S->BackfaceBitmap) && (S->BackfaceBitmap != S->Bitmap) )
01315         {
01316                 if ( geWorld_AddBitmap(World, S->Bitmap) == GE_FALSE )
01317                 {
01318                         geErrorLog_AddString(-1, "Sprite_RenderPrep : World_AddBitmap", NULL);
01319                         return GE_FALSE;
01320                 }
01321         }
01322         
01323         return GE_TRUE;
01324 }
01325 
01326 
01327 geBoolean GENESISCC geSprite_RenderThroughFrustum(geSprite *S, geEngine *Engine, geWorld *World, geCamera *Camera, Frustum_Info *FInfo)
01328 {
01329         int i;
01330         geBoolean Render;
01331         geBoolean RenderBackface;
01332 
01333         assert( geSprite_IsValid(S) );
01334 
01335         // if the sprite always faces the camera, the surface normal and lighting
01336         // may need to be updated
01337         if (S->AlwaysFaceCamera)
01338         {
01339                 // vertexes are needed both to build the final screen poly which is rendered,
01340                 // but also for lighting
01341                 geSprite_UpdateVertexesToFaceCamera(S, Camera);
01342 
01343                 // only modify the surface normal if lighting needs it
01344                 if (S->LightingUsesSurfaceNormal)
01345                 {
01346                         geSprite_UpdateSurfaceNormalToFaceCamera(S, Camera);
01347                         S->LightingChanged = GE_TRUE;
01348                 }
01349 
01350                 // if the sprite uses ambient light from the floor and its transform has
01351                 // changed (transform includes location), then update the lighting
01352                 else if ( (S->TransformChanged) && (S->UseLightFromFloor) )
01353                 {
01354                         S->LightingChanged = GE_TRUE;
01355                 }
01356         }
01357 
01358         // otherwise only update the vertexes if the transform has changed
01359         else if (S->TransformChanged)
01360         {
01361                 // vertexes are needed both to build the final screen poly which is rendered,
01362                 // but also for lighting
01363                 geSprite_UpdateVertexes(S);
01364 
01365                 // update the surface normal
01366                 // this is needed to determine lighting and which face is being viewed
01367                 geSprite_UpdateSurfaceNormal(S);
01368 
01369                 // if the sprite uses the surface normal to light its faces, then
01370                 // update the surface normal and update the lighting
01371                 //
01372                 // if the sprite uses ambient light from the floor and its transform has
01373                 // changed (transform includes location), then update the lighting
01374                 if ( (S->LightingUsesSurfaceNormal) || (S->UseLightFromFloor) )
01375                 {
01376                         S->LightingChanged = GE_TRUE;
01377                 }
01378 
01379                 S->TransformChanged = GE_FALSE;
01380         }
01381 
01382         // generate the frustum clipped screen poly based on the vertexes for the camera
01383         geSprite_CreateFrustumClippedScreenPoly(S, Camera, FInfo, &Render, &RenderBackface);
01384 
01385         // only render if there is something to render
01386         if (Render)
01387         {
01388                 // moved inside here because there is no sense in dynamically
01389                 // lighting the vertexes if they won't be drawn.
01390                 // update the lighting only if lighting has changed or
01391                 // lighting uses dynamic lights (which may change)
01392                 if ( (S->LightingChanged) || (S->MaximumDynamicLightsToUse > 0) )
01393                 {
01394                         geSprite_UpdateLighting(S, World);
01395                         S->LightingChanged = GE_FALSE;
01396                 }
01397 
01398                 // render the poly using the front or backface data
01399                 if (RenderBackface)
01400                 {
01401                         // add the lighting data to the poly
01402                         for (i = 0; i < FrustumNumClippedTexturedLitVertices; i++)
01403                         {
01404                                 FrustumClippedTexturedLitVertexes[i].r = S->BackfaceRGBA.r;
01405                                 FrustumClippedTexturedLitVertexes[i].g = S->BackfaceRGBA.g;
01406                                 FrustumClippedTexturedLitVertexes[i].b = S->BackfaceRGBA.b;
01407                                 FrustumClippedTexturedLitVertexes[i].a = S->BackfaceRGBA.a;
01408                         }
01409 
01410                         // render the poly using the backface bitmap
01411                         geEngine_RenderPoly(Engine, (GE_TLVertex*)FrustumClippedTexturedLitVertexes, FrustumNumClippedTexturedLitVertices, S->BackfaceBitmap, 0);
01412                 }
01413                 else
01414                 {
01415                         // add the lighting data to the poly
01416                         for (i = 0; i < FrustumNumClippedTexturedLitVertices; i++)
01417                         {
01418                                 FrustumClippedTexturedLitVertexes[i].r = S->RGBA.r;
01419                                 FrustumClippedTexturedLitVertexes[i].g = S->RGBA.g;
01420                                 FrustumClippedTexturedLitVertexes[i].b = S->RGBA.b;
01421                                 FrustumClippedTexturedLitVertexes[i].a = S->RGBA.a;
01422                         }
01423 
01424                         // render the poly using the front bitmap
01425                         geEngine_RenderPoly(Engine, (GE_TLVertex*)FrustumClippedTexturedLitVertexes, FrustumNumClippedTexturedLitVertices, S->Bitmap, 0);
01426                 }
01427         }
01428         
01429         return GE_TRUE;
01430 }

Generated on Tue Sep 30 12:36:26 2003 for GTestAndEngine by doxygen 1.3.2