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

Frustum.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  Frustum.c                                                                           */
00003 /*                                                                                      */
00004 /*  Author: John Pollard                                                                */
00005 /*  Description: Frustum creation/clipping                                              */
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 /*  The Original Code is Genesis3D, released March 25, 1999.                            */
00018 /*Genesis3D Version 1.1 released November 15, 1999                            */
00019 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
00020 /*                                                                                      */
00021 /****************************************************************************************/
00022 #include <Assert.h>
00023 #include <Windows.h>
00024 #include <Math.h>
00025 
00026 #include "Camera.h"
00027 #include "Frustum.h"
00028 #include "Surface.h"
00029 
00030 #include "Vec3d.h"
00031 
00032 //#define RIGHT_HANDED
00033 
00034 //=====================================================================================
00035 //      Local Static Function prototypes
00036 //=====================================================================================
00037 static void SetWorldspaceClipPlane(const GFX_Plane *In, const geCamera *Camera, GFX_Plane *Out);
00038 static void BackRotateVector(const geVec3d *In, geVec3d *Out, const geXForm3d *XForm);
00039 static void SetUpFrustumBBox(Frustum_Info *Info);
00040 int Frustum_Seed1=1768710981;
00041 int Frustum_Seed2=560296816;
00042 //================================================================================
00043 //      Frustum_SetFromCamera
00044 //================================================================================
00045 void Frustum_SetFromCamera(Frustum_Info *Info, geCamera *Camera)
00046 {
00047     geFloat             s, c, ZFar;
00048         geBoolean       ZFarEnable;
00049     geVec3d             Normal;
00050         int32           i;
00051 
00052     geCamera_GetViewAngleXSinCos(Camera,&s,&c);
00053 
00054     // Left clip plane
00055     Normal.X = s;
00056     Normal.Y = 0.0f;
00057     Normal.Z = -c;
00058         geVec3d_Normalize(&Normal);
00059         Info->Planes[0].Normal = Normal;
00060 
00061     // Right clip plane
00062     Normal.X = -s;
00063         geVec3d_Normalize(&Normal);
00064         Info->Planes[1].Normal = Normal;
00065 
00066     geCamera_GetViewAngleYSinCos(Camera,&s,&c);
00067 
00068     // Bottom clip plane
00069     Normal.X = 0.0f;
00070     Normal.Y = s;
00071     Normal.Z = -c;
00072         geVec3d_Normalize(&Normal);
00073         Info->Planes[2].Normal = Normal;
00074 
00075     // Top clip plane
00076     Normal.Y = -s;
00077         geVec3d_Normalize(&Normal);
00078         Info->Planes[3].Normal = Normal;
00079 
00080         Info->NumPlanes = 4;
00081 
00082         // Clear all distances
00083         for (i=0; i<Info->NumPlanes; i++)
00084         {
00085                 Info->Planes[i].Dist = 0.0f;
00086                 Info->Planes[i].Type = PLANE_ANY;
00087         }
00088 
00089     // Check to see if we need to use a far clip plane
00090         geCamera_GetFarClipPlane(Camera, &ZFarEnable, &ZFar);
00091 
00092         if (ZFarEnable)
00093         {
00094                 geFloat         ZScale;
00095 
00096                 ZScale = geCamera_GetZScale(Camera);
00097 
00098                 // Far clip plane
00099                 Normal.X = 0.0f;
00100                 Normal.Y = 0.0f;
00101                 Normal.Z = 1.0f;
00102                 geVec3d_Normalize(&Normal);
00103                 Info->Planes[4].Normal = Normal;
00104 
00105                 Info->Planes[4].Dist = -(ZFar/ZScale);
00106                 Info->Planes[4].Type = PLANE_ANY;
00107 
00108                 Info->NumPlanes = 5;
00109         }
00110 
00111         // Get BBox info for fast BBox rejection against frustum...
00112         SetUpFrustumBBox(Info);
00113 }
00114 
00115 //================================================================================
00116 //      Frustum_SetFromPoly
00117 //      Create a frustum looking through a poly (from the origin)
00118 //================================================================================
00119 geBoolean Frustum_SetFromPoly(Frustum_Info *Info, geVec3d *Verts, int32 NumVerts, geBoolean Flip)
00120 {
00121         int32           NextVert;
00122         geVec3d         *pVert1, *pVert2, Vect;
00123         GFX_Plane       *Planes;
00124         int32           i;
00125 
00126         if (NumVerts >= MAX_FCP)
00127                 return GE_FALSE;                // Too many planes!!!
00128         
00129         Planes = Info->Planes;
00130 
00131         Info->NumPlanes = 0;
00132 
00133         for (i=0; i< NumVerts; i++)
00134         {
00135                 NextVert = ((i+1) < NumVerts) ? (i+1) : 0;
00136 
00137                 pVert1 = &Verts[i];
00138                 pVert2 = &Verts[NextVert];
00139 
00140                 if (geVec3d_Compare(pVert1, pVert2, 0.1f))      // Coplanar edge...
00141                         continue;       // Coplanar edges will cause a plane to be duplicated, skip it or it will screw up 
00142                                                 // the clipping stage of the frustum created from this poly...
00143 
00144                 geVec3d_Subtract(pVert1, pVert2, &Vect);
00145                 
00146                 if (Flip)
00147                         geVec3d_CrossProduct(pVert2, &Vect, &Planes->Normal);
00148                 else
00149                         geVec3d_CrossProduct(&Vect, pVert2, &Planes->Normal);
00150 
00151                 geVec3d_Normalize(&Planes->Normal);
00152 
00153                 Planes->Dist = 0.0f;
00154                 Planes->Type = PLANE_ANY;
00155 
00156                 Planes++;
00157                 Info->NumPlanes++;
00158         }
00159 
00160         // Get BBox info for fast BBox rejection against frustum...
00161         SetUpFrustumBBox(Info);
00162 return GE_TRUE;
00163 }
00164 
00165 //================================================================================
00166 //      Frustum_RotateToWorldSpace
00167 //================================================================================
00168 void Frustum_RotateToWorldSpace(Frustum_Info *In, geCamera *Camera, Frustum_Info *Out)
00169 {
00170     int32               i;
00171         GFX_Plane       *pPlane1, *pPlane2;
00172 
00173         assert(In != Out);
00174 
00175         pPlane1 = In->Planes;
00176         pPlane2 = Out->Planes;
00177 
00178         // Rotate all the planes
00179         for (i=0; i<In->NumPlanes; i++, pPlane1++, pPlane2++)
00180         {
00181                 pPlane2->Type = pPlane1->Type;
00182                 
00183                 SetWorldspaceClipPlane(pPlane1, Camera, pPlane2);
00184                 pPlane2->Dist = 0.0f;           // We are just rotating, so set dist to 0
00185 
00186                 if (pPlane1->Dist)              // Add the original dist back in
00187                 {
00188                         geVec3d         Vect;
00189 
00190                         geVec3d_Clear(&Vect);
00191                         geVec3d_AddScaled(&Vect, &pPlane1->Normal, pPlane1->Dist, &Vect);
00192 
00193                         BackRotateVector(&Vect, &Vect, geCamera_GetCameraSpaceXForm(Camera));
00194 
00195                         pPlane2->Dist += geVec3d_DotProduct(&pPlane2->Normal, &Vect);
00196                 }
00197         }
00198 
00199         Out->NumPlanes = In->NumPlanes;
00200 
00201         // Get BBox info for fast BBox rejection against frustum...
00202         SetUpFrustumBBox(Out);
00203 }
00204 
00205 //================================================================================
00206 //      Frustum_TransformToWorldSpace
00207 //================================================================================
00208 void Frustum_TransformToWorldSpace(const Frustum_Info *In, const geCamera *Camera, Frustum_Info *Out)
00209 {
00210     int32               i;
00211         GFX_Plane       *pPlane1, *pPlane2;
00212 
00213         assert(In != Out);
00214 
00215         pPlane1 = (GFX_Plane*)In->Planes;
00216         pPlane2 = Out->Planes;
00217 
00218         // Rotate all the planes
00219         for (i=0; i<In->NumPlanes; i++, pPlane1++, pPlane2++)
00220         {
00221                 pPlane2->Type = pPlane1->Type;
00222                 
00223                 SetWorldspaceClipPlane(pPlane1, Camera, pPlane2);
00224                 pPlane2->Dist = geVec3d_DotProduct(geCamera_GetPov(Camera), &pPlane2->Normal) - CLIP_PLANE_EPSILON;
00225 
00226                 if (pPlane1->Dist)              // Add the original dist back in
00227                 {
00228                         geVec3d         Vect;
00229 
00230                         geVec3d_Clear(&Vect);
00231                         geVec3d_AddScaled(&Vect, &pPlane1->Normal, pPlane1->Dist, &Vect);
00232 
00233                         BackRotateVector(&Vect, &Vect, geCamera_GetCameraSpaceXForm(Camera));
00234 
00235                         pPlane2->Dist += geVec3d_DotProduct(&pPlane2->Normal, &Vect);
00236                 }
00237         }
00238         Out->NumPlanes = In->NumPlanes;
00239 
00240         // Get BBox info for fast BBox rejection against frustum...
00241         SetUpFrustumBBox(Out);
00242 }
00243 
00244 //================================================================================
00245 //      SetWorldSpaceClipPlane
00246 //================================================================================
00247 static void SetWorldspaceClipPlane(const GFX_Plane *In, const geCamera *Camera, GFX_Plane *Out)
00248 {
00249         // Rotate the plane normal into worldspace
00250     BackRotateVector(&In->Normal, &Out->Normal, geCamera_GetCameraSpaceXForm(Camera));
00251 }
00252 
00253 //================================================================================
00254 //      BackRotateVector
00255 //      Rotate a vector from viewspace to worldspace.
00256 //================================================================================
00257 static void BackRotateVector(const geVec3d *In, geVec3d *Out, const geXForm3d *XForm)
00258 {
00259     geVec3d     VRight, VUp, VIn, InCopy;
00260 
00261         InCopy = *In;
00262         
00263         //      Get the 3 vectors that make up the Xform axis 
00264         VRight.X = XForm->AX; VRight.Y = XForm->AY; VRight.Z = XForm->AZ;
00265         VUp.X    = XForm->BX; VUp.Y    = XForm->BY; VUp.Z    = XForm->BZ;
00266         VIn.X    = XForm->CX; VIn.Y    = XForm->CY; VIn.Z    = XForm->CZ;
00267 
00268     Out->X = (InCopy.X * VRight.X) + (InCopy.Y * VUp.X) + (InCopy.Z * VIn.X);
00269     Out->Y = (InCopy.X * VRight.Y) + (InCopy.Y * VUp.Y) + (InCopy.Z * VIn.Y);
00270     Out->Z = (InCopy.X * VRight.Z) + (InCopy.Y * VUp.Z) + (InCopy.Z * VIn.Z);
00271 }
00272 
00273 //================================================================================
00274 //      SetUpFrustumBBox
00275 //      Setup bbox min/max test for the quadrant the frustum planes are in...
00276 //================================================================================
00277 static void SetUpFrustumBBox(Frustum_Info *Info)
00278 {
00279         int32           i, *Index;
00280 
00281         Index = Info->FrustumBBoxIndexes;
00282 
00283         for (i=0 ; i<Info->NumPlanes ; i++)
00284         {
00285                 if (Info->Planes[i].Normal.X < 0)
00286                 {
00287                         Index[0] = 0;
00288                         Index[3] = 3;
00289                 }
00290                 else
00291                 {
00292                         Index[0] = 3;
00293                         Index[3] = 0;
00294                 }
00295                 if (Info->Planes[i].Normal.Y < 0)
00296                 {
00297                         Index[1] = 1;
00298                         Index[4] = 4;
00299                 }
00300                 else
00301                 {
00302                         Index[1] = 4;
00303                         Index[4] = 1;
00304                 }
00305                 if (Info->Planes[i].Normal.Z < 0)
00306                 {
00307                         Index[2] = 2;
00308                         Index[5] = 5;
00309                 }
00310                 else
00311                 {
00312                         Index[2] = 5;
00313                         Index[5] = 2;
00314                 }
00315 
00316                 Info->pFrustumBBoxIndexes[i] = Index;
00317                 Index += 6;
00318         }
00319 }
00320 
00321 //================================================================================
00322 //      gePlane_ClipVertsFanned
00323 //      Clips and adds fanned verts (does not fan though the poly out though...)
00324 //================================================================================
00325 geBoolean gePlane_ClipVertsFanned(      const geVec3d *In, int32 NumIn, 
00326                                                                         const GFX_Plane *Plane, 
00327                                                                         geVec3d *Out, int32 *NumOut)
00328 {
00329         #define MAX_VERT                128
00330 
00331         geVec3d         *pIn, *pOut, *pFirst;
00332         int32           i, Count[2], NextVert;
00333         geFloat         Dist[MAX_VERT];
00334         int32           CurIn, NextIn, FirstIn;
00335         geFloat         CurDist, FirstDist, PlaneDist, NextDist;
00336 
00337         assert(NumIn < MAX_VERT);
00338         
00339         PlaneDist = Plane->Dist;
00340 
00341         pIn = (geVec3d*)In;
00342 
00343         Count[0] = Count[1] = 0;        // Clear front back list
00344 
00345         // First, get all the dist of the verts from the plane
00346         for (i=0; i< NumIn; i++, pIn++)
00347         {
00348                 Dist[i] = geVec3d_DotProduct(&Plane->Normal, pIn) - PlaneDist;
00349 
00350                 if (Dist[i] >= 0.0f)
00351                         Count[0]++;                     // Front side
00352                 else
00353                         Count[1]++;                     // Back side
00354         }
00355 
00356         if (!Count[0])
00357                 return GE_FALSE;                // Poly totally clipped away
00358         else if (!Count[1])     
00359         {
00360                 // Poly was totally in the ViewFrustum so...
00361                 // Copy the poly to the out list
00362                 memcpy((void*)In, Out, sizeof(geVec3d)*NumIn);  
00363                 *NumOut = NumIn;
00364                 return GE_TRUE;
00365         }
00366 
00367     FirstDist = Dist[0];
00368         FirstIn = (FirstDist >= 0.0f);          // Save the first one off for when we are fanning...
00369 
00370         CurDist = FirstDist;                            // Save first as current
00371         CurIn = FirstIn;
00372 
00373         pFirst = pIn = (geVec3d*)In;
00374         pOut = Out;
00375 
00376         // The poly needs to be clipped...
00377         for (i=0; i< NumIn; i++, pIn++)
00378         {
00379                 geVec3d *pNext;
00380 
00381                 NextVert = ((i+1)<NumIn) ? (i+1): 0;
00382 
00383                 if (CurIn)
00384                         *pOut++ = *pIn;
00385 
00386                 pNext = (geVec3d*)&In[NextVert];
00387 
00388                 NextDist = Dist[NextVert];
00389                 NextIn = (NextDist >= 0.0f);
00390 
00391                 // First clip the edges on the poly
00392                 if (CurIn != NextIn)
00393                 {
00394                         geFloat Scale;
00395 
00396                         Scale = (PlaneDist - CurDist) / (NextDist - CurDist);
00397 
00398             pOut->X = pIn->X + (pNext->X - pIn->X) * Scale;
00399             pOut->Y = pIn->Y + (pNext->Y - pIn->Y) * Scale;
00400             pOut->Z = pIn->Z + (pNext->Z - pIn->Z) * Scale;
00401 
00402             pOut++;
00403         }
00404 
00405                 // Start clipping the fanned edges after we get past the first edge
00406                 if (NextVert >= 2)
00407                 {
00408                         if (FirstIn != NextIn)          // The fanned edge crosses the plane, clip it, and store it in the out list
00409                         {
00410                                 geFloat Scale;
00411 
00412                                 Scale = (Plane->Dist - FirstDist) / (NextDist - FirstDist);
00413 
00414                                 pOut->X = pFirst->X + (pNext->X - pFirst->X) * Scale;
00415                                 pOut->Y = pFirst->Y + (pNext->Y - pFirst->Y) * Scale;
00416                                 pOut->Z = pFirst->Z + (pNext->Z - pFirst->Z) * Scale;
00417 
00418                                 pOut++;
00419                         }
00420                 }
00421 
00422         CurIn = NextIn;
00423                 CurDist = NextDist;
00424         }
00425 
00426         *NumOut = (pOut - Out);
00427 
00428         return (*NumOut >= 3);
00429 }
00430 
00431 //================================================================================
00432 //      gePlane_ClipVertsFanned
00433 //      Clips and adds fanned verts (does not fan though the poly out though...)
00434 //================================================================================
00435 geBoolean gePlane_ClipVertsFannedUVRGB( const geVec3d *In, const Surf_TexVert *TIn, int32 NumIn, 
00436                                                                                 const GFX_Plane *Plane, 
00437                                                                                 geVec3d *Out, Surf_TexVert *TOut, int32 *NumOut)
00438 {
00439         #define MAX_VERT                128
00440 
00441         geVec3d                 *pIn, *pOut, *pFirst;
00442         Surf_TexVert    *pTIn, *pTOut, *pTFirst;
00443         int32                   i=0, Count[2], FirstVert=0, NextVert=0;
00444         geFloat                 Dist[MAX_VERT];
00445         int32                   CurIn, NextIn, FirstIn;
00446         geFloat                 CurDist, FirstDist, PlaneDist, NextDist;
00447         int32                   Temp;
00448 
00449         assert(NumIn < MAX_VERT);
00450         
00451         PlaneDist = Plane->Dist;
00452 
00453         pIn = (geVec3d*)In;
00454 
00455         Count[0] = Count[1] = 0;        // Clear front back list
00456 
00457         // First, get all the dist of the verts from the plane
00458         for (i=0; i< NumIn; i++, pIn++)
00459         {
00460                 Dist[i] = geVec3d_DotProduct(&Plane->Normal, pIn);
00461                 
00462                 if (Dist[i] >= PlaneDist)
00463                 {
00464                         Count[0]++;                     // Front side
00465                         FirstVert = i;          // The first vert MUST be inside the frustum
00466                 }
00467                 else
00468                         Count[1]++;                     // Back side
00469                 
00470         }
00471 
00472         if (!Count[0])                          // Nothing on the front
00473                 return GE_FALSE;                
00474         else if (!Count[1])                     // Nothing on the back
00475         {
00476                 // Poly was totally in the ViewFrustum so...
00477                 // Copy the poly to the out list
00478                 memcpy(Out, In, sizeof(geVec3d)*NumIn); 
00479                 memcpy(TOut, TIn, sizeof(Surf_TexVert)*NumIn);  
00480                 *NumOut = NumIn;
00481                 return GE_TRUE;
00482         }
00483 
00484     FirstDist = Dist[FirstVert];
00485         FirstIn = (FirstDist >= PlaneDist);     // Save the first one off for when we are fanning...
00486 
00487         CurDist = FirstDist;                            // Save first as current
00488         CurIn = FirstIn;
00489 
00490         pFirst = pIn = (geVec3d*)&In[FirstVert];
00491         pTFirst = pTIn = (Surf_TexVert*)&TIn[FirstVert];
00492 
00493         pOut = Out;
00494         pTOut = TOut;
00495 
00496         Temp = 0;
00497 
00498         // The poly needs to be clipped...
00499         for (i=FirstVert; i< FirstVert+NumIn; i++, Temp++)
00500         {
00501                 geVec3d                 *pNext;
00502                 Surf_TexVert    *pTNext;
00503                 int32                   ThisVert;
00504 
00505                 ThisVert = i%NumIn;
00506                 NextVert = (i+1)%NumIn;
00507 
00508                 pIn = (geVec3d*)&In[ThisVert];
00509                 pTIn = (Surf_TexVert*)&TIn[ThisVert];
00510 
00511                 if (CurIn)
00512                 {
00513                         *pOut++ = *pIn;
00514                         *pTOut++ = *pTIn;
00515                 }
00516 
00517                 pNext = (geVec3d*)&In[NextVert];
00518                 pTNext = (Surf_TexVert*)&TIn[NextVert];
00519 
00520                 NextDist = Dist[NextVert];
00521                 NextIn = (NextDist >= PlaneDist);
00522 
00523                 // First clip the edges on the poly
00524                 if (CurIn != NextIn)
00525                 {
00526                         geFloat Scale;
00527 
00528                         Scale = (PlaneDist - CurDist) / (NextDist - CurDist);
00529 
00530             pOut->X = pIn->X + (pNext->X - pIn->X) * Scale;
00531             pOut->Y = pIn->Y + (pNext->Y - pIn->Y) * Scale;
00532             pOut->Z = pIn->Z + (pNext->Z - pIn->Z) * Scale;
00533 
00534                         pTOut->u = pTIn->u + (pTNext->u - pTIn->u) * Scale;
00535                         pTOut->v = pTIn->v + (pTNext->v - pTIn->v) * Scale;
00536 
00537                         pTOut->r = pTIn->r + (pTNext->r - pTIn->r) * Scale;
00538                         pTOut->g = pTIn->g + (pTNext->g - pTIn->g) * Scale;
00539                         pTOut->b = pTIn->b + (pTNext->b - pTIn->b) * Scale;
00540 
00541             pOut++;
00542                         pTOut++;
00543         }
00544                 
00545                 // Start clipping the fanned edges after we get past the first edge
00546                 if (Temp >= 1 && Temp+2 < NumIn)
00547                 {
00548                         if (FirstIn != NextIn)          // The fanned edge crosses the plane, clip it, and store it in the out list
00549                         {
00550                                 geFloat Scale;
00551 
00552                                 Scale = (PlaneDist - FirstDist) / (NextDist - FirstDist);
00553 
00554                                 pOut->X = pFirst->X + (pNext->X - pFirst->X) * Scale;
00555                                 pOut->Y = pFirst->Y + (pNext->Y - pFirst->Y) * Scale;
00556                                 pOut->Z = pFirst->Z + (pNext->Z - pFirst->Z) * Scale;
00557 
00558                                 pTOut->u = pTFirst->u + (pTNext->u - pTFirst->u) * Scale;
00559                                 pTOut->v = pTFirst->v + (pTNext->v - pTFirst->v) * Scale;
00560 
00561                                 pTOut->r = pTFirst->r + (pTNext->r - pTFirst->r) * Scale;
00562                                 pTOut->g = pTFirst->g + (pTNext->g - pTFirst->g) * Scale;
00563                                 pTOut->b = pTFirst->b + (pTNext->b - pTFirst->b) * Scale;
00564 
00565                                 pOut++;
00566                                 pTOut++;
00567                         }
00568                 }
00569                 
00570         CurIn = NextIn;
00571                 CurDist = NextDist;
00572         }
00573 
00574         *NumOut = (pOut - Out);
00575 
00576         return (*NumOut >= 3);
00577 }
00578 
00579 //================================================================================
00580 //      Frustum_ClipToPlane
00581 //      Clips X, Y only
00582 //================================================================================
00583 geBoolean Frustum_ClipToPlane(  GFX_Plane *pPlane, 
00584                                                                 geVec3d *pIn, geVec3d *pOut,
00585                                                                 int32 NumVerts, int32 *OutVerts)
00586 {
00587     int32       i, NextVert, CurIn, NextIn;
00588     geFloat     CurDot, NextDot, Scale;
00589     geVec3d     *pInVert, *pOutVert, *pNext;
00590         geVec3d *pNormal;
00591 
00592     pNormal = &pPlane->Normal;
00593         pInVert = pIn;
00594     pOutVert = pOut;
00595 
00596         CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z);
00597     CurIn = (CurDot >= pPlane->Dist);
00598 
00599     for (i=0 ; i<NumVerts ; i++)
00600     {
00601         NextVert = (i + 1);
00602                 if (NextVert == NumVerts)
00603                         NextVert = 0;
00604 
00605         // Keep the current vertex if it's inside the plane
00606         if (CurIn) 
00607             *pOutVert++ = *pInVert;
00608 
00609                 pNext = &pIn[NextVert];
00610                 
00611                 NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z);
00612                 NextIn = (NextDot >= pPlane->Dist);
00613 
00614         // Add a clipped vertex if one end of the current edge is
00615         // inside the plane and the other is outside
00616         if (CurIn != NextIn)
00617         {
00618                         Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot);
00619 
00620             pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale;
00621             pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale;
00622             pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale;
00623 
00624             pOutVert++;
00625         }
00626 
00627         CurDot = NextDot;
00628         CurIn = NextIn;
00629         pInVert++;
00630     }
00631 
00632     *OutVerts = pOutVert - pOut;
00633 
00634     if (*OutVerts < 3)
00635         return GE_FALSE;
00636 
00637     return GE_TRUE;
00638 }
00639 
00640 //================================================================================
00641 //      Frustum_ClipToPlaneUV
00642 //      Clips X, Y, u, v
00643 //================================================================================
00644 geBoolean Frustum_ClipToPlaneUV(        GFX_Plane *pPlane, 
00645                                                                         geVec3d *pIn, geVec3d *pOut,
00646                                                                         Surf_TexVert *pTIn, Surf_TexVert *pTOut,
00647                                                                         int32 NumVerts, int32 *OutVerts)
00648 {
00649     int32               i, NextVert, CurIn, NextIn;
00650     geFloat             CurDot, NextDot, Scale;
00651     geVec3d             *pInVert, *pOutVert, *pNext;
00652     Surf_TexVert *pTInVert, *pTOutVert, *pTNext;
00653         geVec3d         *pNormal;
00654 
00655     pNormal = &pPlane->Normal;
00656         pInVert = pIn;
00657     pOutVert = pOut;
00658         pTInVert = pTIn;
00659     pTOutVert = pTOut;
00660 
00661         CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z);
00662     CurIn = (CurDot >= pPlane->Dist);
00663 
00664     for (i=0 ; i<NumVerts ; i++)
00665     {
00666         NextVert = (i + 1);
00667                 if (NextVert == NumVerts)
00668                         NextVert = 0;
00669 
00670         // Keep the current vertex if it's inside the plane
00671         if (CurIn) 
00672                 {
00673             *pOutVert++ = *pInVert;
00674             // VTune reports this entire copy of this structure is taking alot of time (JP)
00675                         //*pTOutVert++ = *pTInVert;
00676                         pTOutVert->u = pTInVert->u;
00677                         pTOutVert->v = pTInVert->v;
00678                         pTOutVert++;
00679                 }
00680 
00681                 pNext = &pIn[NextVert];
00682                 pTNext = &pTIn[NextVert];
00683                 
00684                 NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z);
00685                 NextIn = (NextDot >= pPlane->Dist);
00686 
00687         // Add a clipped vertex if one end of the current edge is
00688         // inside the plane and the other is outside
00689         if (CurIn != NextIn)
00690         {
00691                         Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot);
00692 
00693             pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale;
00694             pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale;
00695             pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale;
00696 
00697             pTOutVert->u = pTInVert->u + (pTNext->u - pTInVert->u) * Scale;
00698             pTOutVert->v = pTInVert->v + (pTNext->v - pTInVert->v) * Scale;
00699 
00700             pOutVert++;
00701             pTOutVert++;
00702         }
00703 
00704         CurDot = NextDot;
00705         CurIn = NextIn;
00706         pInVert++;
00707         pTInVert++;
00708     }
00709 
00710     *OutVerts = pOutVert - pOut;
00711 
00712     if (*OutVerts < 3)
00713         return GE_FALSE;
00714 
00715     return GE_TRUE;
00716 }
00717 
00718 //================================================================================
00719 //      Frustum_ClipToPlaneUVTGB
00720 //      Clips X, Y, u, v, r, g, b
00721 //================================================================================
00722 geBoolean Frustum_ClipToPlaneUVRGB(GFX_Plane *pPlane, 
00723                                                                         geVec3d *pIn, geVec3d *pOut,
00724                                                                         Surf_TexVert *pTIn, Surf_TexVert *pTOut,
00725                                                                         int32 NumVerts, int32 *OutVerts)
00726 {
00727     int32               i, NextVert, CurIn, NextIn;
00728     geFloat             CurDot, NextDot, Scale;
00729     geVec3d             *pInVert, *pOutVert, *pNext;
00730     Surf_TexVert *pTInVert, *pTOutVert, *pTNext;
00731         geVec3d         *pNormal;
00732 
00733     pNormal = &pPlane->Normal;
00734         pInVert = pIn;
00735     pOutVert = pOut;
00736         pTInVert = pTIn;
00737     pTOutVert = pTOut;
00738 
00739         CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z);
00740     CurIn = (CurDot >= pPlane->Dist);
00741 
00742     for (i=0 ; i<NumVerts ; i++)
00743     {
00744         NextVert = (i + 1);
00745                 if (NextVert == NumVerts)
00746                         NextVert = 0;
00747 
00748         // Keep the current vertex if it's inside the plane
00749         if (CurIn) 
00750                 {
00751             *pOutVert++ = *pInVert;
00752             *pTOutVert++ = *pTInVert;
00753                 }
00754 
00755                 pNext = &pIn[NextVert];
00756                 pTNext = &pTIn[NextVert];
00757                 
00758                 NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z);
00759                 NextIn = (NextDot >= pPlane->Dist);
00760 
00761         // Add a clipped vertex if one end of the current edge is
00762         // inside the plane and the other is outside
00763         if (CurIn != NextIn)
00764         {
00765                         Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot);
00766 
00767             pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale;
00768             pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale;
00769             pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale;
00770 
00771             pTOutVert->u = pTInVert->u + (pTNext->u - pTInVert->u) * Scale;
00772             pTOutVert->v = pTInVert->v + (pTNext->v - pTInVert->v) * Scale;
00773 
00774             pTOutVert->r = pTInVert->r + (pTNext->r - pTInVert->r) * Scale;
00775             pTOutVert->g = pTInVert->g + (pTNext->g - pTInVert->g) * Scale;
00776             pTOutVert->b = pTInVert->b + (pTNext->b - pTInVert->b) * Scale;
00777 
00778             pOutVert++;
00779             pTOutVert++;
00780         }
00781 
00782         CurDot = NextDot;
00783         CurIn = NextIn;
00784         pInVert++;
00785         pTInVert++;
00786     }
00787 
00788     *OutVerts = pOutVert - pOut;
00789 
00790     if (*OutVerts < 3)
00791         return GE_FALSE;
00792 
00793     return GE_TRUE;
00794 }
00795 
00796 //================================================================================
00797 //      Frustum_ClipToPlaneUVTGB
00798 //      Clips X, Y, u, v, r, g, b, a
00799 //================================================================================
00800 geBoolean Frustum_ClipToPlaneUVRGBA(GFX_Plane *pPlane, 
00801                                                                         geVec3d *pIn, geVec3d *pOut,
00802                                                                         Surf_TexVert *pTIn, Surf_TexVert *pTOut,
00803                                                                         int32 NumVerts, int32 *OutVerts)
00804 {
00805     int32               i, NextVert, CurIn, NextIn;
00806     geFloat             CurDot, NextDot, Scale;
00807     geVec3d             *pInVert, *pOutVert, *pNext;
00808     Surf_TexVert *pTInVert, *pTOutVert, *pTNext;
00809         geVec3d         *pNormal;
00810 
00811     pNormal = &pPlane->Normal;
00812         pInVert = pIn;
00813     pOutVert = pOut;
00814         pTInVert = pTIn;
00815     pTOutVert = pTOut;
00816 
00817         CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z);
00818     CurIn = (CurDot >= pPlane->Dist);
00819 
00820     for (i=0 ; i<NumVerts ; i++)
00821     {
00822         NextVert = (i + 1);
00823                 if (NextVert == NumVerts)
00824                         NextVert = 0;
00825 
00826         // Keep the current vertex if it's inside the plane
00827         if (CurIn) 
00828                 {
00829             *pOutVert++ = *pInVert;
00830             *pTOutVert++ = *pTInVert;
00831                 }
00832 
00833                 pNext = &pIn[NextVert];
00834                 pTNext = &pTIn[NextVert];
00835                 
00836                 NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z);
00837                 NextIn = (NextDot >= pPlane->Dist);
00838 
00839         // Add a clipped vertex if one end of the current edge is
00840         // inside the plane and the other is outside
00841         if (CurIn != NextIn)
00842         {
00843                         Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot);
00844 
00845             pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale;
00846             pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale;
00847             pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale;
00848 
00849             pTOutVert->u = pTInVert->u + (pTNext->u - pTInVert->u) * Scale;
00850             pTOutVert->v = pTInVert->v + (pTNext->v - pTInVert->v) * Scale;
00851 
00852             pTOutVert->r = pTInVert->r + (pTNext->r - pTInVert->r) * Scale;
00853             pTOutVert->g = pTInVert->g + (pTNext->g - pTInVert->g) * Scale;
00854             pTOutVert->b = pTInVert->b + (pTNext->b - pTInVert->b) * Scale;
00855             pTOutVert->a = pTInVert->a + (pTNext->a - pTInVert->a) * Scale;
00856 
00857             pOutVert++;
00858             pTOutVert++;
00859         }
00860 
00861         CurDot = NextDot;
00862         CurIn = NextIn;
00863         pInVert++;
00864         pTInVert++;
00865     }
00866 
00867     *OutVerts = pOutVert - pOut;
00868 
00869     if (*OutVerts < 3)
00870         return GE_FALSE;
00871 
00872     return GE_TRUE;
00873 }
00874 
00875 //================================================================================
00876 //      Frustum_ClipToPlaneRGB
00877 //      Clips X, Y, r, g, b
00878 //================================================================================
00879 geBoolean Frustum_ClipToPlaneRGB(       GFX_Plane *pPlane, 
00880                                                                         geVec3d *pIn, geVec3d *pOut,
00881                                                                         Surf_TexVert *pTIn, Surf_TexVert *pTOut,
00882                                                                         int32 NumVerts, int32 *OutVerts)
00883 {
00884     int32               i, NextVert, CurIn, NextIn;
00885     geFloat             CurDot, NextDot, Scale;
00886     geVec3d             *pInVert, *pOutVert, *pNext;
00887     Surf_TexVert *pTInVert, *pTOutVert, *pTNext;
00888         geVec3d         *pNormal;
00889 
00890     pNormal = &pPlane->Normal;
00891         pInVert = pIn;
00892     pOutVert = pOut;
00893         pTInVert = pTIn;
00894     pTOutVert = pTOut;
00895 
00896         CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z);
00897     CurIn = (CurDot >= pPlane->Dist);
00898 
00899     for (i=0 ; i<NumVerts ; i++)
00900     {
00901         NextVert = (i + 1);
00902                 if (NextVert == NumVerts)
00903                         NextVert = 0;
00904 
00905         // Keep the current vertex if it's inside the plane
00906         if (CurIn) 
00907                 {
00908             *pOutVert++ = *pInVert;
00909             *pTOutVert++ = *pTInVert;
00910                 }
00911 
00912                 pNext = &pIn[NextVert];
00913                 pTNext = &pTIn[NextVert];
00914                 
00915                 NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z);
00916                 NextIn = (NextDot >= pPlane->Dist);
00917 
00918         // Add a clipped vertex if one end of the current edge is
00919         // inside the plane and the other is outside
00920         if (CurIn != NextIn)
00921         {
00922                         Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot);
00923 
00924             pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale;
00925             pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale;
00926             pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale;
00927 
00928             pTOutVert->r = pTInVert->r + (pTNext->r - pTInVert->r) * Scale;
00929             pTOutVert->g = pTInVert->g + (pTNext->g - pTInVert->g) * Scale;
00930             pTOutVert->b = pTInVert->b + (pTNext->b - pTInVert->b) * Scale;
00931 
00932             pOutVert++;
00933             pTOutVert++;
00934         }
00935 
00936         CurDot = NextDot;
00937         CurIn = NextIn;
00938         pInVert++;
00939         pTInVert++;
00940     }
00941 
00942     *OutVerts = pOutVert - pOut;
00943 
00944     if (*OutVerts < 3)
00945         return GE_FALSE;
00946 
00947     return GE_TRUE;
00948 }
00949 
00950 //================================================================================
00951 //      Frustum_Project
00952 //================================================================================
00953 void Frustum_Project(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera)
00954 {  
00955         int32                   i;
00956         geVec3d                 Out;
00957 
00958         assert( pIn    != NULL);
00959         assert( pTIn   != NULL);
00960         assert( pOut   != NULL);  
00961         assert( Camera != NULL);
00962 
00963         for (i=0; i<NumVerts; i++)
00964         {
00965                 geCamera_ProjectAndClamp( Camera, &pIn[i], &Out );
00966                 pOut->x = Out.X;
00967                 pOut->y = Out.Y;
00968                 pOut->z = Out.Z;
00969         pOut->u = pTIn->u;  
00970                 pOut->v = pTIn->v; 
00971 
00972                 pOut++;
00973                 pTIn++;
00974         }
00975 }
00976 
00977 //================================================================================
00978 //      Frustum_Project
00979 //================================================================================
00980 void Frustum_ProjectRGB(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera)
00981 {  
00982         int32   i;
00983         geVec3d Out;
00984 
00985         assert( pIn    != NULL);
00986         assert( pTIn   != NULL);
00987         assert( pOut   != NULL);  
00988         assert( Camera != NULL);
00989 
00990         for (i=0; i<NumVerts; i++)
00991         {
00992                 geCamera_ProjectAndClamp( Camera, &pIn[i], &Out );
00993                 pOut->x = Out.X;
00994                 pOut->y = Out.Y;
00995                 pOut->z = Out.Z;
00996 
00997         pOut->u = pTIn->u;  
00998                 pOut->v = pTIn->v; 
00999         pOut->r = pTIn->r;  
01000                 pOut->g = pTIn->g; 
01001                 pOut->b = pTIn->b; 
01002 
01003                 pOut++;
01004                 pTIn++;
01005         }
01006 }
01007 
01008 //================================================================================
01009 //      Frustum_Project
01010 //================================================================================
01011 void Frustum_ProjectRGBA(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera)
01012 {  
01013         int32   i;
01014         geVec3d Out;
01015         assert( pIn    != NULL);
01016         assert( pTIn   != NULL);
01017         assert( pOut   != NULL);  
01018         assert( Camera != NULL);
01019 
01020         for (i=0; i<NumVerts; i++)
01021         {
01022                 geCamera_ProjectAndClamp( Camera, &pIn[i], &Out );
01023                 pOut->x = Out.X;
01024                 pOut->y = Out.Y;
01025                 pOut->z = Out.Z;
01026                 pOut->u = pTIn->u;  
01027                 pOut->v = pTIn->v; 
01028         pOut->r = pTIn->r;  
01029                 pOut->g = pTIn->g; 
01030                 pOut->b = pTIn->b; 
01031                 pOut->a = pTIn->a; 
01032 
01033                 pOut++;
01034                 pTIn++;
01035         }
01036 }
01037 
01038 //================================================================================
01039 //      Frustum_Project
01040 //================================================================================
01041 void Frustum_ProjectRGBNoClamp(geVec3d *pIn, Surf_TexVert *pTIn, DRV_TLVertex *pOut, int32 NumVerts, const geCamera *Camera)
01042 {  
01043         int32   i;
01044         geVec3d Out;
01045         assert( pIn    != NULL);
01046         assert( pTIn   != NULL);
01047         assert( pOut   != NULL);  
01048         assert( Camera != NULL);
01049 
01050         for (i=0; i<NumVerts; i++)
01051         {
01052                 geCamera_Project( Camera, &pIn[i], &Out );
01053                 pOut->x = Out.X;
01054                 pOut->y = Out.Y;
01055                 pOut->z = Out.Z;
01056         
01057         pOut->u = pTIn->u;  
01058                 pOut->v = pTIn->v; 
01059         pOut->r = pTIn->r;  
01060                 pOut->g = pTIn->g; 
01061                 pOut->b = pTIn->b; 
01062 
01063                 pOut++;
01064                 pTIn++;
01065         }
01066 }
01067 
01068 //================================================================================
01069 //      Frustum_PointsInFrustum
01070 //================================================================================
01071 geBoolean Frustum_PointsInFrustum(const geVec3d *Pin, const GFX_Plane *Plane, int32 NumVerts, int32 *c)
01072 {
01073     int32       Count, i;
01074 
01075         Count = 0;
01076 
01077         for (i=0; i< NumVerts; i++)
01078         {
01079                 if (geVec3d_DotProduct(Pin, &Plane->Normal) >= Plane->Dist)
01080                         Count++;
01081 
01082                 Pin++;
01083         }
01084 
01085         *c += Count;
01086 
01087         return Count;
01088 }
01089 
01090 //================================================================================
01091 //      Frustum_PointInFrustum
01092 //================================================================================
01093 geBoolean Frustum_PointInFrustum(const Frustum_Info *Fi, const geVec3d *Point, geFloat Radius)
01094 {
01095         int32                   i;
01096         const GFX_Plane *Plane;
01097         geFloat                 Dist;
01098 
01099         Plane = Fi->Planes;
01100 
01101         for (i=0; i< Fi->NumPlanes; i++, Plane++)
01102         {
01103                 Dist = geVec3d_DotProduct(Point, &Plane->Normal) - Plane->Dist;
01104 
01105                 Dist += Radius;
01106 
01107                 if (Dist < 0)                   // Behind plane
01108                         return GE_FALSE;
01109 
01110         }
01111 
01112         return GE_TRUE;
01113 }
01114 
01115 //================================================================================
01116 //      Frustum_ClipAllPlanesL  (CB added)
01117 //================================================================================
01118 geBoolean Frustum_ClipAllPlanesL(const Frustum_Info * Fi,uint32 ClipFlags,GE_LVertex *Verts, int32 *pNumVerts)
01119 {
01120 uint32 mask;
01121 GE_LVertex WorkVerts[32];
01122 GE_LVertex *p1,*p2,*p3;
01123 GFX_Plane * FPlane;
01124 
01125         p1 = Verts;
01126         p2 = WorkVerts;
01127         
01128         FPlane = (GFX_Plane *)Fi->Planes;
01129 
01130         for(mask=1; mask <= ClipFlags; mask += mask, FPlane++)
01131         {
01132                 if ( ! (ClipFlags & mask) )
01133                         continue;
01134 
01135                 if (!Frustum_ClipToPlaneL(FPlane, p1,p2, *pNumVerts,pNumVerts) )
01136                         return GE_FALSE;
01137 
01138                 if ( (*pNumVerts) < 3 || (*pNumVerts) > 30 )
01139                         return GE_FALSE;
01140 
01141                 p3 = p1;
01142                 p1 = p2;
01143                 p2 = p3;
01144         }
01145 
01146         if ( p1 != Verts )
01147         {
01148                 memcpy(Verts,p1,sizeof(GE_LVertex)*(*pNumVerts));
01149         }
01150 
01151 return GE_TRUE;
01152 }
01153 
01154 //================================================================================
01155 //      Frustum_ClipToPlaneL    (CB added)
01156 //================================================================================
01157 geBoolean Frustum_ClipToPlaneL(GFX_Plane *pPlane, 
01158                                                                 GE_LVertex *pIn, GE_LVertex *pOut,
01159                                                                 int32 NumVerts, int32 *NumOutVerts)
01160 {
01161     int32               i, NextVert, CurIn, NextIn;
01162     geFloat             CurDot, NextDot, Scale;
01163     GE_LVertex  *pInVert, *pOutVert, *pNext;
01164         geVec3d         *pNormal;
01165 
01166     pNormal = &pPlane->Normal;
01167         pInVert = pIn;
01168     pOutVert = pOut;
01169 
01170         CurDot = (pInVert->X * pNormal->X) + (pInVert->Y * pNormal->Y) + (pInVert->Z * pNormal->Z);
01171     CurIn = (CurDot >= pPlane->Dist);
01172 
01173     for (i=0 ; i<NumVerts ; i++)
01174     {
01175         NextVert = (i + 1);
01176                 if (NextVert == NumVerts)
01177                         NextVert = 0;
01178 
01179         // Keep the current vertex if it's inside the plane
01180         if (CurIn) 
01181                 {
01182             *pOutVert++ = *pInVert;
01183                 }
01184 
01185                 pNext = &pIn[NextVert];
01186                 
01187                 NextDot = (pNext->X * pNormal->X) + (pNext->Y * pNormal->Y) + (pNext->Z * pNormal->Z);
01188                 NextIn = (NextDot >= pPlane->Dist);
01189 
01190         // Add a clipped vertex if one end of the current edge is
01191         // inside the plane and the other is outside
01192         if (CurIn != NextIn)
01193         {
01194                         Scale = (pPlane->Dist - CurDot) / (NextDot - CurDot);
01195 
01196             pOutVert->X = pInVert->X + (pNext->X - pInVert->X) * Scale;
01197             pOutVert->Y = pInVert->Y + (pNext->Y - pInVert->Y) * Scale;
01198             pOutVert->Z = pInVert->Z + (pNext->Z - pInVert->Z) * Scale;
01199 
01200             pOutVert->u = pInVert->u + (pNext->u - pInVert->u) * Scale;
01201             pOutVert->v = pInVert->v + (pNext->v - pInVert->v) * Scale;
01202 
01203             pOutVert->r = pInVert->r + (pNext->r - pInVert->r) * Scale;
01204             pOutVert->g = pInVert->g + (pNext->g - pInVert->g) * Scale;
01205             pOutVert->b = pInVert->b + (pNext->b - pInVert->b) * Scale;
01206             pOutVert->a = pInVert->a + (pNext->a - pInVert->a) * Scale;
01207 
01208             pOutVert++;
01209         }
01210 
01211         CurDot = NextDot;
01212         CurIn = NextIn;
01213         pInVert++;
01214     }
01215 
01216     *NumOutVerts = ((uint32)pOutVert - (uint32)pOut)/sizeof(*pOut);
01217 
01218     if ( *NumOutVerts < 3)
01219         return GE_FALSE;
01220 
01221 return GE_TRUE;
01222 }
01223 

Generated on Tue Sep 30 12:35:44 2003 for GTestAndEngine by doxygen 1.3.2