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

QKFrame.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  QKFRAME.H                                                                                                                                                   */
00003 /*                                                                                      */
00004 /*  Author: Mike Sandige                                                                    */
00005 /*  Description: Quaternion keyframe 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 /*  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 /* geQKFrame   (geQuaternion - Keyframe)
00023         This module handles interpolation for keyframes that contain a quaternion
00024         This is intended to support Path.c
00025         geTKArray supplies general support for a time-keyed array, and this supplements
00026         that support to include the specific time-keyed arrays:
00027           An array of geQuaternion interpolated linearly
00028           An array of geQuaternion with spherical linear interpolation (SLERP)
00029           An array of geQuaternion with spherical quadrangle 
00030                 interpolation (SQUAD) as defined by:
00031             Advanced Animation and Rendering Techniques by Alan Watt and Mark Watt
00032 
00033         These are phycially separated and have different base structures because
00034         the different interpolation techniques requre different additional data.
00035         
00036         The two lists are created with different creation calls,
00037         interpolated with different calls, but insertion and queries share a call.
00038         
00039         Quadrangle interpolation requires additional computation after changes are
00040         made to the keyframe list.  Call geQKFrame_SquadRecompute() to update the
00041         calculations.
00042 */
00043 #include <assert.h>
00044 #include <string.h>
00045 #include <stdio.h>
00046 
00047 #include "vec3d.h"
00048 #include "QKFrame.h"
00049 #include "errorlog.h"
00050 #include "ram.h"
00051 
00052 #define LINEAR_BLEND(a,b,t)  ( (t)*((b)-(a)) + (a) )    
00053                         // linear blend of a and b  0<t<1 where  t=0 ->a and t=1 ->b
00054 
00055 typedef struct
00056 {
00057         geTKArray_TimeType      Time;                           // Time for this keyframe
00058         geQuaternion    Q;                                      // quaternion for this keyframe
00059 }  QKeyframe;           
00060         // This is the root structure that geQKFrame supports
00061         // all keyframe types must begin with this structure.  Time is first, so
00062         // that this structure can be manipulated by geTKArray
00063 
00064 typedef struct
00065 {
00066         QKeyframe Key;                          // key values for this keyframe
00067 }       geQKFrame_Linear;
00068         // keyframe data for linear interpolation
00069         // The structure includes no additional information.
00070 
00071 typedef struct
00072 {
00073         QKeyframe Key;                          // key values for this keyframe
00074 }       geQKFrame_Slerp;
00075         // keyframe data for spherical linear interpolation
00076         // The structure includes no additional information.
00077 
00078 typedef struct
00079 {
00080         QKeyframe Key;                          // key values for this keyframe
00081         geQuaternion  QuadrangleCorner; 
00082 }       geQKFrame_Squad;
00083         // keyframe data for spherical quadratic interpolation
00084 
00085 
00086 geTKArray *GENESISCC geQKFrame_LinearCreate()
00087         // creates a frame list for linear interpolation
00088 {
00089         return geTKArray_Create(sizeof(geQKFrame_Linear) );
00090 }
00091 
00092 
00093 geTKArray *GENESISCC geQKFrame_SlerpCreate()
00094         // creates a frame list for spherical linear interpolation      
00095 {
00096         return geTKArray_Create(sizeof(geQKFrame_Slerp) );
00097 }
00098 
00099 geTKArray *GENESISCC geQKFrame_SquadCreate()
00100         // creates a frame list for spherical linear interpolation      
00101 {
00102         return geTKArray_Create(sizeof(geQKFrame_Squad) );
00103 }
00104 
00105 
00106 geBoolean GENESISCC geQKFrame_Insert(
00107         geTKArray **KeyList,                    // keyframe list to insert into
00108         geTKArray_TimeType Time,                // time of new keyframe
00109         const geQuaternion *Q,                  // quaternion at new keyframe
00110         int *Index)                                             // index of new key
00111         // inserts a new keyframe with the given time and vector into the list.
00112 {
00113         assert( KeyList != NULL );
00114         assert( *KeyList != NULL );
00115         assert( Q != NULL );
00116         assert(   sizeof(geQKFrame_Squad) == geTKArray_ElementSize(*KeyList) 
00117                || sizeof(geQKFrame_Slerp) == geTKArray_ElementSize(*KeyList) 
00118                    || sizeof(geQKFrame_Linear) == geTKArray_ElementSize(*KeyList) );
00119 
00120         if (geTKArray_Insert(KeyList, Time, Index) == GE_FALSE)
00121                 {
00122                         geErrorLog_Add(ERR_QKARRAY_INSERT, NULL);
00123                         return GE_FALSE;
00124                 }
00125         else
00126                 {
00127                         QKeyframe *KF;
00128                         KF = (QKeyframe *)geTKArray_Element(*KeyList,*Index);
00129                         KF->Q = *Q;
00130                         return GE_TRUE;
00131                 }
00132 }
00133 
00134 void GENESISCC geQKFrame_Query(
00135         const geTKArray *KeyList,               // keyframe list
00136         int Index,                                              // index of frame to return
00137         geTKArray_TimeType *Time,               // time of the frame is returned
00138         geQuaternion *Q)                                        // vector from the frame is returned
00139         // returns the vector and the time at keyframe[index] 
00140 {
00141         QKeyframe *KF;
00142         assert( KeyList != NULL );
00143         assert( Time != NULL );
00144         assert( Q != NULL );
00145         assert( Index < geTKArray_NumElements(KeyList) );
00146         assert( Index >= 0 );
00147         assert(   sizeof(geQKFrame_Squad) == geTKArray_ElementSize(KeyList) 
00148                || sizeof(geQKFrame_Slerp) == geTKArray_ElementSize(KeyList) 
00149                    || sizeof(geQKFrame_Linear) == geTKArray_ElementSize(KeyList) );
00150         
00151         KF = (QKeyframe *)geTKArray_Element(KeyList,Index);
00152         *Time = KF->Time;
00153         *Q    = KF->Q;
00154 }
00155 
00156 void GENESISCC geQKFrame_Modify(
00157         geTKArray *KeyList,                             // keyframe list
00158         int Index,                                              // index of frame to change
00159         const geQuaternion *Q)                  // vector for the new key
00160 {
00161         QKeyframe *KF;
00162         assert( KeyList != NULL );
00163         assert( Q != NULL );
00164         assert( Index < geTKArray_NumElements(KeyList) );
00165         assert( Index >= 0 );
00166         assert(   sizeof(geQKFrame_Squad) == geTKArray_ElementSize(KeyList) 
00167                || sizeof(geQKFrame_Slerp) == geTKArray_ElementSize(KeyList) 
00168                    || sizeof(geQKFrame_Linear) == geTKArray_ElementSize(KeyList) );
00169         
00170         KF = (QKeyframe *)geTKArray_Element(KeyList,Index);
00171         KF->Q  = *Q;
00172 }
00173 
00174 
00175 
00176 void GENESISCC geQKFrame_LinearInterpolation(
00177         const void *KF1,                // pointer to first keyframe
00178         const void *KF2,                // pointer to second keyframe
00179         geFloat T,                              // 0 <= T <= 1   blending parameter
00180         void *Result)                   // put the result in here (geQuaternion)
00181                 // interpolates to get a vector between the two vectors at the two
00182                 // keyframes where T==0 returns the vector for KF1 
00183                 // and T==1 returns the vector for KF2
00184                 // interpolates linearly
00185 {
00186         geQuaternion *Q1,*Q2;
00187         geQuaternion *QNew = (geQuaternion *)Result;
00188         
00189         assert( Result != NULL );
00190         assert( KF1 != NULL );
00191         assert( KF2 != NULL );
00192         
00193         assert( T >= (geFloat)0.0f );
00194         assert( T <= (geFloat)1.0f );
00195         
00196         if ( KF1 == KF2 )
00197                 {
00198                         *QNew = ((geQKFrame_Linear *)KF1)->Key.Q;
00199                         return;
00200                 }
00201 
00202         Q1 = &( ((geQKFrame_Linear *)KF1)->Key.Q);
00203         Q2 = &( ((geQKFrame_Linear *)KF2)->Key.Q);
00204         
00205         QNew->X = LINEAR_BLEND(Q1->X,Q2->X,T);
00206         QNew->Y = LINEAR_BLEND(Q1->Y,Q2->Y,T);
00207         QNew->Z = LINEAR_BLEND(Q1->Z,Q2->Z,T);
00208         QNew->W = LINEAR_BLEND(Q1->W,Q2->W,T);
00209         if (geQuaternion_Normalize(QNew)==0.0f)
00210                 {
00211                         geQuaternion_SetNoRotation(QNew);
00212                 }
00213 
00214 }
00215 
00216 
00217 
00218 void GENESISCC geQKFrame_SlerpInterpolation(
00219         const void *KF1,                // pointer to first keyframe
00220         const void *KF2,                // pointer to second keyframe
00221         geFloat T,                              // 0 <= T <= 1   blending parameter
00222         void *Result)                   // put the result in here (geQuaternion)
00223                 // interpolates to get a vector between the two vectors at the two
00224                 // keyframes where T==0 returns the vector for KF1 
00225                 // and T==1 returns the vector for KF2
00226                 // interpolates using spherical linear blending
00227 {
00228         geQuaternion *Q1,*Q2;
00229         geQuaternion *QNew = (geQuaternion *)Result;
00230         
00231         assert( Result != NULL );
00232         assert( KF1 != NULL );
00233         assert( KF2 != NULL );
00234         
00235         assert( T >= (geFloat)0.0f );
00236         assert( T <= (geFloat)1.0f );
00237         
00238         if ( KF1 == KF2 )
00239                 {
00240                         *QNew = ((geQKFrame_Slerp *)KF1)->Key.Q;
00241                         return;
00242                 }
00243  
00244         Q1 = &( ((geQKFrame_Slerp *)KF1)->Key.Q);
00245         Q2 = &( ((geQKFrame_Slerp *)KF2)->Key.Q);
00246         geQuaternion_SlerpNotShortest(Q1,Q2,T,QNew);
00247 }
00248 
00249 
00250 
00251 
00252 void GENESISCC geQKFrame_SquadInterpolation(
00253         const void *KF1,                // pointer to first keyframe
00254         const void *KF2,                // pointer to second keyframe
00255         geFloat T,                              // 0 <= T <= 1   blending parameter
00256         void *Result)                   // put the result in here (geQuaternion)
00257                 // interpolates to get a vector between the two vectors at the two
00258                 // keyframes where T==0 returns the vector for KF1 
00259                 // and T==1 returns the vector for KF2
00260                 // interpolates using spherical quadratic blending
00261 {
00262         geQuaternion *Q1,*Q2;
00263         geQuaternion *QNew = (geQuaternion *)Result;
00264         
00265         assert( Result != NULL );
00266         assert( KF1 != NULL );
00267         assert( KF2 != NULL );
00268         
00269         assert( T >= (geFloat)0.0f );
00270         assert( T <= (geFloat)1.0f );
00271         
00272         if ( KF1 == KF2 )
00273                 {
00274                         *QNew = ((geQKFrame_Squad *)KF1)->Key.Q;
00275                         return;
00276                 }
00277 
00278         Q1 = &( ((geQKFrame_Squad *)KF1)->Key.Q);
00279         Q2 = &( ((geQKFrame_Squad *)KF2)->Key.Q);
00280         
00281         {
00282                 geQuaternion *A1,*B2;
00283                 geQuaternion SL1,SL2;
00284                                 
00285                 A1 = &( ((geQKFrame_Squad *)KF1)->QuadrangleCorner);
00286                 B2 = &( ((geQKFrame_Squad *)KF2)->QuadrangleCorner);
00287 
00288                 geQuaternion_SlerpNotShortest(Q1,   Q2,   T, &SL1);
00289                                 assert( geQuaternion_IsUnit(&SL1) == GE_TRUE);
00290                 geQuaternion_SlerpNotShortest(A1,   B2,   T, &SL2);
00291                                 assert( geQuaternion_IsUnit(&SL2) == GE_TRUE);
00292                 geQuaternion_SlerpNotShortest(&SL1, &SL2, (2.0f*T*(1.0f-T)), QNew);
00293                                 assert( geQuaternion_IsUnit(QNew) == GE_TRUE);
00294         }
00295 }
00296 
00297 
00298 static void GENESISCC geQKFrame_QuadrangleCorner(
00299         const geQuaternion *Q0,
00300         const geQuaternion *Q1,
00301         const geQuaternion *Q2,
00302         geQuaternion *Corner)
00303         // compute quadrangle corner for a keyframe containing Q1.
00304         //  Q0 and Q2 are the quaternions for the previous and next keyframes 
00305         // corner is the newly computed quaternion
00306 {
00307         geQuaternion Q1Inv,LnSum;
00308 
00309         assert( Q0 != NULL );
00310         assert( Q1 != NULL );
00311         assert( Q2 != NULL );
00312         assert( Corner != NULL );
00313 
00314         assert( geQuaternion_IsUnit(Q1) == GE_TRUE );
00315 
00316         Q1Inv.W = Q1->W;
00317         Q1Inv.X = -Q1->X;
00318         Q1Inv.Y = -Q1->Y;
00319         Q1Inv.Z = -Q1->Z;
00320                                 
00321         {
00322                 geQuaternion Q1InvQ2, Q1InvQ0;
00323                 geQuaternion Ln1,Ln2;
00324 
00325                 geQuaternion_Multiply(&Q1Inv,Q2,&Q1InvQ2);
00326                 geQuaternion_Multiply(&Q1Inv,Q0,&Q1InvQ0);
00327                 geQuaternion_Ln(&Q1InvQ0,&Ln1);
00328                 geQuaternion_Ln(&Q1InvQ2,&Ln2);
00329                 geQuaternion_Add(&Ln1,&Ln2,&LnSum);
00330                 geQuaternion_Scale(&LnSum,-0.25f,&LnSum);
00331         }
00332 
00333         geQuaternion_Exp(&LnSum,Corner);
00334         geQuaternion_Multiply(Q1,Corner,Corner);
00335 }
00336 
00337 static void GENESISCC geQKFrame_ChooseBestQuat(const geQuaternion *Q0,geQuaternion *Q1)
00338         // adjusts the sign of Q1:  to either Q1 or -Q1
00339         // adjusts Q1 such that Q1 is the 'closest' of the two choices to Q0.
00340 {
00341         geQuaternion pLessQ,pPlusQ;
00342         geFloat MagpLessQ,MagpPlusQ;
00343 
00344         assert( Q0 != NULL );
00345         assert( Q1 != NULL );
00346         
00347         geQuaternion_Add(Q0,Q1,&pPlusQ);
00348         geQuaternion_Subtract(Q0,Q1,&pLessQ);
00349                 
00350         geQuaternion_Multiply(&pPlusQ,&pPlusQ,&pPlusQ);
00351         geQuaternion_Multiply(&pLessQ,&pLessQ,&pLessQ);
00352 
00353         MagpLessQ=   (pLessQ.W * pLessQ.W) + (pLessQ.X * pLessQ.X) 
00354                                           + (pLessQ.Y * pLessQ.Y) + (pLessQ.Z * pLessQ.Z);
00355 
00356         MagpPlusQ=   (pPlusQ.W * pPlusQ.W) + (pPlusQ.X * pPlusQ.X) 
00357                                           + (pPlusQ.Y * pPlusQ.Y) + (pPlusQ.Z * pPlusQ.Z);
00358 
00359         if (MagpLessQ >= MagpPlusQ)
00360                 {
00361                         Q1->X = -Q1->X;
00362                         Q1->Y = -Q1->Y;
00363                         Q1->Z = -Q1->Z;
00364                         Q1->W = -Q1->W;
00365                 }
00366 }
00367 
00368 
00369 
00370 
00371 void GENESISCC geQKFrame_SquadRecompute(
00372         int Looped,                             // if keylist has the first key connected to last key
00373         geTKArray *KeyList)             // list of keys to recompute hermite values for
00374         // rebuild precomputed data for keyframe list.
00375 {
00376 
00377         // compute the extra interpolation points at each keyframe
00378         // see Advanced Animation and Rendering Techniques 
00379         //     by Alan Watt and Mark Watt, pg 366
00380         int i;
00381         geQKFrame_Squad *QList=NULL;
00382         int count;
00383 
00384         int Index0,Index1,Index2;
00385         assert( KeyList != NULL );
00386 
00387         count = geTKArray_NumElements(KeyList);
00388 
00389         if (count > 0)
00390                 {
00391                         QList = (geQKFrame_Squad *)geTKArray_Element(KeyList,0);
00392 
00393                         for (i =0; i< count-1; i++)
00394                                 {
00395                                         geQKFrame_ChooseBestQuat(&(QList[i].Key.Q),&(QList[i+1].Key.Q) );
00396                                 }
00397                 }
00398 
00399         if (count<3)
00400                 {
00401                         Looped = 0;
00402                         // cant compute 'slopes' without enough points to loop. 
00403                         // so treat path as non-looped.
00404                 }
00405         for (i =0; i< count; i++)
00406                 {
00407                         Index0 = i-1;
00408                         Index1 = i;
00409                         Index2 = i+1;
00410 
00411                         if (Index1 == 0)
00412                                 {
00413                                         if (Looped != GE_TRUE)
00414                                                 {
00415                                                         Index0 = 0;
00416                                                 }
00417                                         else
00418                                                 {
00419                                                         Index0 = count-2;
00420                                                 }
00421                                 }
00422 
00423                         if (Index2 == count)
00424                                 {
00425                                         if (Looped != GE_TRUE)
00426                                                 {
00427                                                         Index2 = count-1;
00428                                                 }
00429                                         else
00430                                                 {
00431                                                         Index2 = 1;
00432                                                 }
00433                                 }
00434 
00435                         if (( Looped != GE_TRUE) && (Index1 == 0) )
00436                                 {
00437                                         geQuaternion_Copy(
00438                                                 &(QList[i].Key.Q),
00439                                                 &(QList[i].QuadrangleCorner) );
00440                                 }
00441                         else if (( Looped != GE_TRUE) && (Index1 == count-1))
00442                                 {
00443                                         geQuaternion_Copy(
00444                                                 &(QList[i].Key.Q),
00445                                                 &(QList[i].QuadrangleCorner) );
00446                                 }
00447                         else
00448                         {
00449                                 geQKFrame_QuadrangleCorner( 
00450                                         &(QList[Index0].Key.Q),
00451                                         &(QList[Index1].Key.Q),
00452                                         &(QList[Index2].Key.Q),
00453                                         &(QList[i].QuadrangleCorner) );
00454         
00455                         }
00456                 }       
00457 }                                       
00458 
00459 
00460 
00461 void GENESISCC geQKFrame_SlerpRecompute(
00462         geTKArray *KeyList)             // list of keys to recompute hermite values for
00463         // rebuild precomputed data for keyframe list.
00464         // also make sure that each successive key is the 'closest' quaternion choice
00465         // to the previous one.
00466 {
00467 
00468         int i;
00469         geQKFrame_Slerp *QList;
00470         int count;
00471         assert( KeyList != NULL );
00472 
00473         count = geTKArray_NumElements(KeyList);
00474 
00475         if (count > 0)
00476                 {
00477                         QList = (geQKFrame_Slerp  *)geTKArray_Element(KeyList,0);
00478                         for (i =0; i< count-1; i++)
00479                                 {
00480                                         geQKFrame_ChooseBestQuat(&(QList[i].Key.Q),&(QList[i+1].Key.Q) );
00481                                 }
00482                 }
00483 }
00484 
00485 
00486 #define QKFRAME_LINEAR_ASCII_FILE 0x4C464B51    // 'QKFL'
00487 #define QKFRAME_SLERP_ASCII_FILE 0x53464B51             // 'QKFS'
00488 #define QKFRAME_SQUAD_ASCII_FILE 0x51464B51             // 'QKFQ'
00489 #define CHECK_FOR_WRITE(uu) if(uu <= 0)     { geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL); return GE_FALSE; }
00490 #define CHECK_FOR_READ(uu, nn) if(uu != nn) { geErrorLog_Add(ERR_PATH_FILE_READ, NULL);  return GE_FALSE; }
00491 
00492 #define QKFRAME_KEYLIST_ID "Keys"
00493 
00494 //------------------------------------------------------------------------
00495 // support for older data files
00496 
00497 geBoolean GENESISCC geQKFrame_LinearRead(geVFile* pFile, void* geQKFrame)
00498 {
00499         uint32  u;
00500         char    QKeyString[64];
00501         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geQKFrame;
00502 
00503         assert( pFile != NULL );
00504         assert( geQKFrame != NULL );
00505 
00506         // Read the format/version flag
00507         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
00508         {
00509                 geErrorLog_Add(ERR_PATH_FILE_READ, NULL);
00510                 return GE_FALSE;
00511         }
00512 
00513         if(u != QKFRAME_LINEAR_ASCII_FILE)
00514         {
00515                 geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL);
00516                 return GE_FALSE;
00517         }
00518 
00519         if      (geVFile_GetS(pFile, QKeyString, sizeof(QKeyString)) == GE_FALSE)
00520         {
00521                 geErrorLog_Add(ERR_PATH_FILE_READ, NULL);
00522                 return GE_FALSE;
00523         }
00524 
00525         u = sscanf(QKeyString, "%f %f %f %f\n", &pLinear->Key.Q.W,
00526                                                                                         &pLinear->Key.Q.X,
00527                                                                                         &pLinear->Key.Q.Y,
00528                                                                                         &pLinear->Key.Q.Z);
00529         CHECK_FOR_READ(u, 4);
00530 
00531         return GE_TRUE;
00532 }
00533 
00534 geBoolean GENESISCC geQKFrame_SlerpRead(geVFile* pFile, void* geQKFrame)
00535 {
00536         uint32  u;
00537         char    QKeyString[64];
00538         geQKFrame_Slerp* pSlerp = (geQKFrame_Slerp*)geQKFrame;
00539 
00540         assert( pFile != NULL );
00541         assert( geQKFrame != NULL );
00542 
00543         // Read the format/version flag
00544         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
00545         {
00546                 geErrorLog_Add(ERR_PATH_FILE_READ, NULL);
00547                 return GE_FALSE;
00548         }
00549 
00550         if(u != QKFRAME_SLERP_ASCII_FILE)
00551         {
00552                 geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL);
00553                 return GE_FALSE;
00554         }
00555 
00556         if      (geVFile_GetS(pFile, QKeyString, sizeof(QKeyString)) == GE_FALSE)
00557         {
00558                 geErrorLog_Add(ERR_PATH_FILE_READ, NULL);
00559                 return GE_FALSE;
00560         }
00561 
00562         u = sscanf(QKeyString, "%f %f %f %f\n", &pSlerp->Key.Q.W,
00563                                                                                         &pSlerp->Key.Q.X,
00564                                                                                         &pSlerp->Key.Q.Y,
00565                                                                                         &pSlerp->Key.Q.Z);
00566         CHECK_FOR_READ(u, 4);
00567 
00568         return GE_TRUE;
00569 }
00570 
00571 
00572 geBoolean GENESISCC geQKFrame_SquadRead(geVFile* pFile, void* geQKFrame)
00573 {
00574         uint32  u;
00575         char    SQuadKeyString[128];
00576         geQKFrame_Squad* pSquad = (geQKFrame_Squad*)geQKFrame;
00577 
00578         assert( pFile != NULL );
00579         assert( geQKFrame != NULL );
00580 
00581         // Read the format/version flag
00582         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
00583         {
00584                 geErrorLog_Add(ERR_PATH_FILE_READ, NULL);
00585                 return GE_FALSE;
00586         }
00587 
00588         if(u != QKFRAME_SQUAD_ASCII_FILE)
00589         {
00590                 geErrorLog_Add(ERR_PATH_FILE_VERSION, NULL);
00591                 return GE_FALSE;
00592         }
00593 
00594         if      (geVFile_GetS(pFile, SQuadKeyString, sizeof(SQuadKeyString)) == GE_FALSE)
00595         {
00596                 geErrorLog_Add(ERR_PATH_FILE_READ, NULL);
00597                 return GE_FALSE;
00598         }
00599 
00600         u = sscanf(SQuadKeyString, "%f %f %f %f %f %f %f %f\n", &pSquad->Key.Q.W,
00601                                                                                                                         &pSquad->Key.Q.X,
00602                                                                                                                         &pSquad->Key.Q.Y,
00603                                                                                                                         &pSquad->Key.Q.Z,
00604                                                                                                                         &pSquad->QuadrangleCorner.W,
00605                                                                                                                         &pSquad->QuadrangleCorner.X,
00606                                                                                                                         &pSquad->QuadrangleCorner.Y,
00607                                                                                                                         &pSquad->QuadrangleCorner.Z);
00608         CHECK_FOR_READ(u, 8);
00609 
00610         return GE_TRUE;
00611 }
00612 
00613 //------------------------------------------------------------------------
00614 #define QKFRAME_HINGE_COMPRESSION 0x1
00615 #define QKFRAME_LINEARTIME_COMPRESSION 0x2
00616 
00617 
00618 #define HINGE_TOLERANCE (0.0001f)
00619 #define LINEARTIME_TOLERANCE (0.0001f)
00620 
00621 static geBoolean GENESISCC geQKFrame_PathIsHinged(geTKArray *KeyList, geFloat Tolerance)
00622 {
00623         int i,Count;
00624         geVec3d Axis;
00625         geVec3d NextAxis;
00626         geFloat Angle; 
00627         geQKFrame_Linear* pLinear;
00628 
00629         assert( KeyList != NULL );
00630 
00631         Count = geTKArray_NumElements(KeyList);
00632         
00633         if (Count<2)
00634                 return GE_FALSE;
00635         pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0);
00636         if (geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Axis,&Angle)==GE_FALSE)
00637                 {
00638                         return GE_FALSE;
00639                 }
00640                 
00641         for (i=1; i<Count; i++)
00642                 {
00643                         pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
00644                         if (geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&NextAxis,&Angle)==GE_FALSE)
00645                                 {
00646                                         return GE_FALSE;
00647                                 }
00648                                 
00649                         if (geVec3d_Compare(&Axis,&NextAxis,Tolerance) == GE_FALSE)
00650                                 {       
00651                                         return GE_FALSE;
00652                                 }
00653                 }
00654         return GE_TRUE;
00655 }
00656 
00657 
00658 static int GENESISCC geQKFrame_DetermineCompressionType(geTKArray *KeyList)
00659 {
00660         int Compression=0;
00661         int NumElements=0;
00662 
00663         assert( KeyList != NULL );
00664 
00665         NumElements = geTKArray_NumElements(KeyList);
00666 
00667         if (NumElements>2)
00668                 {
00669                         if ( geTKArray_SamplesAreTimeLinear(KeyList,LINEARTIME_TOLERANCE) != GE_FALSE )
00670                                 {
00671                                         Compression |= QKFRAME_LINEARTIME_COMPRESSION;
00672                                 }
00673                 }
00674 
00675 
00676         if (NumElements>3)
00677                 {
00678                          if ( geQKFrame_PathIsHinged(KeyList,HINGE_TOLERANCE)!=GE_FALSE )
00679                                 {
00680                                         Compression |= QKFRAME_HINGE_COMPRESSION;
00681                                 }
00682                 }
00683 
00684         return Compression;
00685 }
00686 
00687 
00688 
00689 geBoolean GENESISCC geQKFrame_WriteToFile(geVFile *pFile, geTKArray *KeyList, 
00690                 geQKFrame_InterpolationType InterpolationType, int Looping)
00691 {
00692         int NumElements,i;
00693         geFloat Time,DeltaTime;
00694         int Compression;
00695 
00696         assert( pFile != NULL );
00697         assert( KeyList != NULL );
00698 
00699         NumElements = geTKArray_NumElements(KeyList);
00700         
00701         Compression = geQKFrame_DetermineCompressionType(KeyList);
00702 
00703         if      (geVFile_Printf(pFile,
00704                                           "%s %d %d %d %d\n",
00705                                           QKFRAME_KEYLIST_ID,
00706                                           NumElements,
00707                                           InterpolationType,
00708                                           Compression,
00709                                           Looping) == GE_FALSE)
00710                 {
00711                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00712                         return GE_FALSE;
00713                 }
00714 
00715         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
00716                 {
00717                         Time = geTKArray_ElementTime(KeyList, 0);
00718                         DeltaTime = geTKArray_ElementTime(KeyList, 1)- Time;
00719                         if      (geVFile_Printf(pFile,"%f %f Start T,Delta T\n",Time,DeltaTime) == GE_FALSE)
00720                                 {
00721                                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00722                                         return GE_FALSE;
00723                                 }
00724                 }
00725 
00726         switch (Compression & (~QKFRAME_LINEARTIME_COMPRESSION) )
00727                 {
00728                         case (0):
00729                                 {
00730                                         for(i=0;i<NumElements;i++)
00731                                                 {
00732                                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
00733                                                         if (!(Compression & QKFRAME_LINEARTIME_COMPRESSION))
00734                                                                 {
00735                                                                         Time = geTKArray_ElementTime(KeyList, i);
00736                                                                         if      (geVFile_Printf(pFile, "%f ",Time) == GE_FALSE)
00737                                                                                 {
00738                                                                                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00739                                                                                         return GE_FALSE;
00740                                                                                 }
00741                                                                 }
00742                                                         if      (geVFile_Printf(pFile,
00743                                                                                           "%f %f %f %f\n",      pLinear->Key.Q.W,  pLinear->Key.Q.X,  
00744                                                                                                                                 pLinear->Key.Q.Y,  pLinear->Key.Q.Z) == GE_FALSE)
00745                                                                 {
00746                                                                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00747                                                                         return GE_FALSE;
00748                                                                 }
00749                                                 }
00750                                 }
00751                                 break;
00752                         case (QKFRAME_HINGE_COMPRESSION):
00753                                 {
00754                                         geVec3d Hinge;
00755                                         geFloat Angle;
00756 
00757                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0);
00758                                         geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Hinge,&Angle);
00759                                         geVec3d_Normalize(&Hinge);
00760                                         if      (geVFile_Printf(pFile,"%f %f %f Axis\n",Hinge.X,Hinge.Y,Hinge.Z) == GE_FALSE)
00761                                                 {
00762                                                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00763                                                         return GE_FALSE;
00764                                                 }
00765                                         for(i=0;i<NumElements;i++)
00766                                                 {
00767                                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
00768                                                         if (!(Compression & QKFRAME_LINEARTIME_COMPRESSION))
00769                                                                 {
00770                                                                         Time = geTKArray_ElementTime(KeyList, i);
00771                                                                         if      (geVFile_Printf(pFile, "%f ",Time) == GE_FALSE)
00772                                                                                 {
00773                                                                                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00774                                                                                         return GE_FALSE;
00775                                                                                 }
00776                                                                 }
00777                                                         geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Hinge,&Angle);
00778                                                         if      (geVFile_Printf(pFile,"%f\n",   Angle) == GE_FALSE)
00779                                                                 {
00780                                                                         geErrorLog_Add(ERR_PATH_FILE_WRITE, NULL);
00781                                                                         return GE_FALSE;
00782                                                                 }
00783                                                 }
00784                                 }
00785                                 break;
00786                         default:
00787                                 assert(0);
00788 
00789                 }
00790         return GE_TRUE;
00791 }
00792 
00793 
00794 geTKArray *GENESISCC geQKFrame_CreateFromFile(geVFile *pFile, int *InterpolationType, int *Looping)
00795 {
00796         int i,u,NumElements;
00797         int Compression;
00798         geFloat StartTime=0.0f;
00799         geFloat DeltaTime=0.0f;
00800 
00801         #define ERROREXIT  {geErrorLog_Add( ERR_PATH_FILE_READ, NULL);if (KeyList != NULL){geTKArray_Destroy(&KeyList);}        return NULL;}
00802 
00803         #define LINE_LENGTH 256
00804         char line[LINE_LENGTH];
00805         geTKArray *KeyList=NULL;
00806 
00807         assert( pFile != NULL );
00808         assert( InterpolationType != NULL );
00809         
00810         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
00811                 ERROREXIT;
00812         if(strnicmp(line, QKFRAME_KEYLIST_ID, sizeof(QKFRAME_KEYLIST_ID)-1) != 0)
00813                 ERROREXIT;
00814 
00815         if(sscanf(line + sizeof(QKFRAME_KEYLIST_ID)-1, "%d %d %d %d", 
00816                                         &NumElements,InterpolationType,&Compression,Looping) != 4)
00817                 ERROREXIT;
00818 
00819         if (!( (*InterpolationType == QKFRAME_LINEAR) || (*InterpolationType == QKFRAME_SLERP) || (*InterpolationType == QKFRAME_SQUAD) ))
00820                 ERROREXIT;
00821         
00822         if ( Compression > 0xFF)
00823                 ERROREXIT;
00824                 
00825 
00826 
00827         switch (*InterpolationType)
00828                 {
00829                         case (QKFRAME_LINEAR):
00830                                         KeyList = geTKArray_CreateEmpty(sizeof(geQKFrame_Linear),NumElements);
00831                                         break;
00832                         case (QKFRAME_SLERP):
00833                                         KeyList = geTKArray_CreateEmpty(sizeof(geQKFrame_Slerp),NumElements);
00834                                         break;
00835                         case (QKFRAME_SQUAD):
00836                                         KeyList = geTKArray_CreateEmpty(sizeof(geQKFrame_Squad),NumElements);
00837                                         break;
00838                         default:
00839                                 ERROREXIT;
00840                 }
00841         if (KeyList == NULL)
00842                 ERROREXIT;
00843 
00844         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
00845                 {
00846                         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
00847                                 ERROREXIT;
00848                         if (sscanf(line,"%f %f",&StartTime,&DeltaTime) != 2)
00849                                 ERROREXIT;
00850                 }
00851         switch (Compression & (~QKFRAME_LINEARTIME_COMPRESSION) )
00852                 {
00853                         case (0):
00854                                 {
00855                                         for(i=0;i<NumElements;i++)
00856                                                 {
00857                                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
00858                                                         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
00859                                                                 ERROREXIT;
00860                                                         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
00861                                                                 {
00862                                                                         pLinear->Key.Time = StartTime + DeltaTime * i;
00863                                                                         u = sscanf(line,"%f %f %f %f", &(pLinear->Key.Q.W),
00864                                                                                 &(pLinear->Key.Q.X),&(pLinear->Key.Q.Y),&(pLinear->Key.Q.Z));
00865                                                                         if (u==4) u = 5;
00866                                                                 }
00867                                                         else
00868                                                                 {
00869                                                                         u = sscanf(line,"%f %f %f %f %f",&(pLinear->Key.Time), &(pLinear->Key.Q.W),
00870                                                                                 &(pLinear->Key.Q.X),&(pLinear->Key.Q.Y),&(pLinear->Key.Q.Z));
00871                                                                 }
00872                                                         if (u!=5)
00873                                                                 ERROREXIT;
00874                                                 }
00875                                 }
00876                                 break;
00877                         case (QKFRAME_HINGE_COMPRESSION):
00878                                 {
00879                                         geVec3d Hinge;
00880                                         geFloat Angle;
00881                                         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
00882                                                 ERROREXIT;
00883                                         u = sscanf(line,"%f %f %f",&(Hinge.X),&(Hinge.Y),&(Hinge.Z) );
00884                                         if (u != 3)
00885                                                 ERROREXIT;
00886                                         for(i=0;i<NumElements;i++)
00887                                                 {
00888                                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
00889                                                         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
00890                                                                 ERROREXIT;
00891                                                         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
00892                                                                 {
00893                                                                         pLinear->Key.Time = StartTime + DeltaTime * i;
00894                                                                         u = sscanf(line,"%f", &(Angle));
00895                                                                         if (u==1) u = 2;
00896                                                                 }
00897                                                         else
00898                                                                 {
00899                                                                         u = sscanf(line,"%f %f",&(pLinear->Key.Time), &(Angle) );
00900                                                                 }
00901                                                         if (u!=2)
00902                                                                 ERROREXIT;
00903                                                         geQuaternion_SetFromAxisAngle(&(pLinear->Key.Q),&Hinge,Angle);
00904                                                 }
00905                                 }
00906                                 break;
00907                         default:
00908                                 assert(0);
00909 
00910                 }
00911 
00912         switch (*InterpolationType)
00913                 {
00914                         case (QKFRAME_LINEAR):
00915                                         break;
00916                         case (QKFRAME_SLERP):
00917                                 geQKFrame_SlerpRecompute( KeyList);
00918                                         break;
00919                         case (QKFRAME_SQUAD):
00920                                 geQKFrame_SquadRecompute( *Looping, KeyList);
00921                                         break;
00922                         default:
00923                                 assert(0);
00924                 }
00925         return KeyList; 
00926 
00927 }
00928 
00929 uint32 GENESISCC geQKFrame_ComputeBlockSize(geTKArray *KeyList, int Compression)
00930 {
00931         uint32 Size=0;
00932         int Count;
00933         assert( KeyList != NULL );
00934         assert( Compression < 0xFF);
00935         
00936         Count = geTKArray_NumElements(KeyList);
00937 
00938         Size += sizeof(uint32);         // flags
00939         Size += sizeof(uint32);         // count
00940 
00941         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
00942                 {
00943                         Size += sizeof(geFloat) * 2;
00944                 }
00945         else
00946                 {
00947                         Size += sizeof(geFloat) * Count;
00948                 }
00949 
00950         switch (Compression & (~QKFRAME_LINEARTIME_COMPRESSION) )
00951                 {
00952                         case 0:
00953                                 Size += sizeof(geQuaternion) * Count;
00954                                 break;
00955                         case QKFRAME_HINGE_COMPRESSION:
00956                                 Size += (sizeof(geFloat) * 3) + sizeof(geFloat) * Count;
00957                                 break;
00958                         default:
00959                                 assert(0);
00960                 }       
00961         return Size;
00962 }
00963 
00964 geTKArray *GENESISCC geQKFrame_CreateFromBinaryFile(geVFile *pFile, int *InterpolationType, int *Looping)
00965 {
00966         uint32 u;
00967         int BlockSize;
00968         int Compression;
00969         int Count,i;
00970         int FieldSize;
00971         char *Block;
00972         geFloat *Data;
00973         geTKArray *KeyList;
00974         geQKFrame_Linear* pLinear0;
00975         geQKFrame_Linear* pLinear;
00976 
00977         assert( pFile != NULL );
00978         assert( InterpolationType != NULL );
00979         assert( Looping != NULL );
00980         
00981         if (geVFile_Read(pFile, &BlockSize, sizeof(int)) == GE_FALSE)
00982                 {
00983                         geErrorLog_AddString(-1,"Failure to read binary QKFrame header", NULL);
00984                         return NULL;
00985                 }
00986         if (BlockSize<0)
00987                 {
00988                         geErrorLog_AddString(-1,"Bad Blocksize", NULL);
00989                         return NULL;
00990                 }
00991                         
00992         Block = geRam_Allocate(BlockSize);
00993         if(geVFile_Read(pFile, Block, BlockSize) == GE_FALSE)
00994                 {
00995                         geErrorLog_AddString(-1,"Failure to read binary QKFrame header", NULL);
00996                         return NULL;
00997                 }
00998         u = *(uint32 *)Block;
00999         *InterpolationType = (u>>16)& 0xFF;
01000         Compression = (u>>8) & 0xFF;
01001         *Looping           = (u & 0x1);         
01002         Count = *(((uint32 *)Block)+1);
01003         
01004         if (Compression > 0xFF)
01005                 {
01006                         geRam_Free(Block);      
01007                         geErrorLog_AddString(-1,"Bad Compression Flag", NULL);
01008                         return NULL;
01009                 }
01010         switch (*InterpolationType)
01011                 {
01012                         case (QKFRAME_LINEAR):
01013                                 FieldSize = sizeof(geQKFrame_Linear);
01014                                 break;
01015                         case (QKFRAME_SLERP):
01016                                 FieldSize = sizeof(geQKFrame_Slerp);
01017                                 break;
01018                         case (QKFRAME_SQUAD):
01019                                 FieldSize = sizeof(geQKFrame_Squad);
01020                                 break;
01021                         default:
01022                                 geRam_Free(Block);
01023                                 geErrorLog_AddString(-1,"Bad InterpolationType", NULL);
01024                                 return NULL;
01025                 }
01026         
01027         KeyList = geTKArray_CreateEmpty(FieldSize,Count);
01028         if (KeyList == NULL)
01029                 {
01030                         geRam_Free(Block);      
01031                         geErrorLog_AddString(-1,"Failed to allocate tkarray", NULL);
01032                         return NULL;
01033                 }
01034 
01035         Data = (geFloat *)(Block + sizeof(uint32)*2);
01036                         
01037         pLinear0 = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0);
01038 
01039         pLinear = pLinear0;
01040 
01041         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
01042                 {
01043                         geFloat fi;
01044                         geFloat fCount = (geFloat)Count;
01045                         geFloat Time,DeltaTime;
01046                         Time = *(Data++);
01047                         DeltaTime = *(Data++);
01048                         for(fi=0.0f;fi<fCount;fi+=1.0f)
01049                                 {
01050                                         pLinear->Key.Time = Time + fi*DeltaTime;
01051                                         pLinear = (geQKFrame_Linear *)  ( ((char *)pLinear) + FieldSize );
01052                                 }
01053                 }
01054         else
01055                 {
01056                         for(i=0;i<Count;i++)
01057                                 {
01058                                         pLinear->Key.Time = *(Data++);
01059                                         pLinear = (geQKFrame_Linear *)  ( ((char *)pLinear) + FieldSize );
01060                                 }
01061                 }
01062 
01063         pLinear = pLinear0;
01064 
01065         if (Compression & QKFRAME_HINGE_COMPRESSION)
01066                 {
01067                         geVec3d Hinge;
01068                         Hinge.X = *(Data++);
01069                         Hinge.Y = *(Data++);
01070                         Hinge.Z = *(Data++);
01071 
01072                         for(i=0;i<Count;i++)
01073                                 {
01074                                         geQuaternion_SetFromAxisAngle(&(pLinear->Key.Q),&Hinge,*(Data++));
01075                                         pLinear = (geQKFrame_Linear *)  ( ((char *)pLinear) + FieldSize );
01076                                 }
01077                 }
01078         else
01079                 {
01080                         for(i=0;i<Count;i++)
01081                                 {
01082                                         pLinear->Key.Q = *(geQuaternion *)Data;
01083                                         Data += 4;
01084                                         pLinear = (geQKFrame_Linear *)  ( ((char *)pLinear) + FieldSize );
01085                                 }
01086                 }
01087         
01088         switch (*InterpolationType)
01089                 {
01090                         case (QKFRAME_LINEAR):
01091                                         break;
01092                         case (QKFRAME_SLERP):
01093                                 geQKFrame_SlerpRecompute( KeyList);
01094                                         break;
01095                         case (QKFRAME_SQUAD):
01096                                 geQKFrame_SquadRecompute( *Looping, KeyList);
01097                                         break;
01098                         default:
01099                                 assert(0);
01100                 }
01101         geRam_Free(Block);      
01102         return KeyList;                                         
01103 }
01104 
01105 geBoolean GENESISCC geQKFrame_WriteToBinaryFile(geVFile *pFile, geTKArray *KeyList, 
01106                 geQKFrame_InterpolationType InterpolationType, int Looping)
01107 {
01108         #define WBERREXIT  {geErrorLog_AddString( ERR_PATH_FILE_WRITE,"Failure to write binary key data", NULL);return GE_FALSE;}
01109         uint32 u,BlockSize;
01110         int Compression;
01111         int Count,i;
01112         geFloat Time,DeltaTime;
01113         assert( pFile != NULL );
01114         assert( InterpolationType < 0xFF);
01115         assert( (Looping == 0) || (Looping == 1) );
01116 
01117 
01118         Compression = geQKFrame_DetermineCompressionType(KeyList);
01119         u = (InterpolationType << 16) | (Compression << 8) |  Looping;
01120         
01121         BlockSize = geQKFrame_ComputeBlockSize(KeyList,Compression);
01122 
01123         if (geVFile_Write(pFile, &BlockSize,sizeof(uint32)) == GE_FALSE)
01124                 WBERREXIT;
01125         
01126         if (geVFile_Write(pFile, &u, sizeof(uint32)) == GE_FALSE)
01127                 WBERREXIT;
01128         
01129         Count = geTKArray_NumElements(KeyList);
01130         if (geVFile_Write(pFile, &Count, sizeof(uint32)) == GE_FALSE)
01131                 WBERREXIT;
01132         
01133         if (Compression & QKFRAME_LINEARTIME_COMPRESSION)
01134                 {
01135                         Time = geTKArray_ElementTime(KeyList, 0);
01136                         DeltaTime = geTKArray_ElementTime(KeyList, 1)- Time;
01137                         if (geVFile_Write(pFile, &Time,sizeof(geFloat)) == GE_FALSE)
01138                                 WBERREXIT;
01139                         if (geVFile_Write(pFile, &DeltaTime,sizeof(geFloat)) == GE_FALSE)
01140                                 WBERREXIT;
01141                 }
01142         else
01143                 {
01144                         for(i=0;i<Count;i++)
01145                                 {
01146                                         Time = geTKArray_ElementTime(KeyList, i);
01147                                         if (geVFile_Write(pFile, &Time,sizeof(geFloat)) == GE_FALSE)
01148                                                 WBERREXIT;
01149                                 }
01150                 }
01151 
01152         if (Compression & QKFRAME_HINGE_COMPRESSION)
01153                 {
01154                         geVec3d Hinge;
01155                         geFloat Angle;
01156 
01157                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, 0);
01158                         geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Hinge,&Angle);
01159                         geVec3d_Normalize(&Hinge);
01160                         if (geVFile_Write(pFile, &Hinge,sizeof(geVec3d)) == GE_FALSE)
01161                                 WBERREXIT;
01162 
01163                         for(i=0;i<Count;i++)
01164                                 {
01165                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
01166                                         geQuaternion_GetAxisAngle(&(pLinear->Key.Q),&Hinge,&Angle);
01167                                         if (geVFile_Write(pFile, &Angle,sizeof(geFloat)) == GE_FALSE)
01168                                                 WBERREXIT;
01169                                 }
01170                 }
01171         else
01172                 {
01173                         for(i=0;i<Count;i++)
01174                                 {
01175                                         geQKFrame_Linear* pLinear = (geQKFrame_Linear*)geTKArray_Element(KeyList, i);
01176                                         if (geVFile_Write(pFile, &(pLinear->Key.Q),sizeof(geQuaternion)) == GE_FALSE)
01177                                                 WBERREXIT;
01178                                 }
01179                 }
01180                 
01181         return GE_TRUE;
01182 }

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