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

path.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  PATH.C                                                                                                                                                              */
00003 /*                                                                                      */
00004 /*  Author: Mike Sandige                                                                    */
00005 /*  Description: Time-indexed keyframe creation, maintenance, and sampling.                             */
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 <math.h>   //fmod()
00024 #include <string.h>
00025 #include <stdio.h>  //sscanf
00026 
00027 #include "path.h"
00028 #include "Quatern.h"
00029 #include "errorlog.h"
00030 #include "ram.h"
00031 #include "tkarray.h"
00032 #include "VKFrame.h"
00033 #include "QKFrame.h"
00034 #include "vec3d.h"
00035 
00036 #define min(aa,bb)  (( (aa)>(bb) ) ? (bb) : (aa) )
00037 #define max(aa,bb)  (( (aa)>(bb) ) ? (aa) : (bb) )
00038 
00039 
00040 #define gePath_TimeType geFloat
00041 
00042 typedef int8 Bool8;
00043 
00044 typedef void (GENESISCC *InterpolationFunction)(
00045         const void *KF1,
00046         const void *KF2, 
00047         gePath_TimeType T,
00048         void *Result);
00049 
00050 
00051 #define FLAG_DIRTY   (0x01)
00052 #define FLAG_LOOPED  (0x01)
00053 #define FLAG_OTHER       (0x696C6345)
00054 #define FLAG_EMPTY       (0x21657370)
00055 
00056 typedef struct
00057 {
00058         geTKArray *KeyList;
00059         int InterpolationType;                          // type of interpolation for channel
00060 
00061         gePath_TimeType StartTime;                      // First time in channel's path
00062         gePath_TimeType EndTime;                        // Last time in channel's path
00063 
00064         // --remember keys used for last sample--
00065         int32 LastKey1;                                         // smaller key
00066         int32 LastKey2;                                         // larger key (keys may be equal)
00067         gePath_TimeType LastKey1Time;           // Time at LastKey1
00068         gePath_TimeType LastKey2Time;           // Time at LastKey2
00069                                                                         // if last key is not valid: LastKey1Time > LastKey2Time
00070 } gePath_Channel;
00071 
00072 
00073 typedef struct _gePath
00074 {
00075         gePath_Channel Rotation;
00076         gePath_Channel Translation;
00077         unsigned int Dirty   : 1;                                               
00078         unsigned int Looped  : 1;
00079         unsigned int RefCount:30;
00080 } gePath;
00081 
00082 typedef enum
00083 {
00084         GE_PATH_VK_LINEAR,
00085         GE_PATH_VK_HERMITE,
00086         GE_PATH_VK_HERMITE_ZERO_DERIV,
00087         GE_PATH_QK_LINEAR,
00088         GE_PATH_QK_SLERP,
00089         GE_PATH_QK_SQUAD,
00090         GE_PATH_MANY_INTERPOLATORS
00091 } gePath_InterpolationType;
00092 
00093 typedef struct 
00094 {
00095         InterpolationFunction InterpolationTable[GE_PATH_MANY_INTERPOLATORS];
00096         int32 Flags[2];
00097 } gePath_StaticType;
00098 
00099 gePath_StaticType gePath_Statics = 
00100 {
00101         {       geVKFrame_LinearInterpolation,
00102                 geVKFrame_HermiteInterpolation,
00103                 geVKFrame_HermiteInterpolation,
00104                 geQKFrame_LinearInterpolation,
00105                 geQKFrame_SlerpInterpolation,
00106                 geQKFrame_SquadInterpolation
00107         },
00108         {FLAG_OTHER,FLAG_EMPTY}
00109 };
00110 
00111 
00112 static geVKFrame_InterpolationType GENESISCC gePath_PathToVKInterpolation(gePath_InterpolationType I)
00113 {
00114         switch (I)
00115                 {
00116                         case (GE_PATH_VK_LINEAR):                         return VKFRAME_LINEAR;
00117                         case (GE_PATH_VK_HERMITE):                        return VKFRAME_HERMITE;
00118                         case (GE_PATH_VK_HERMITE_ZERO_DERIV): return VKFRAME_HERMITE_ZERO_DERIV;
00119                         default: assert(0);
00120                 }
00121         return VKFRAME_LINEAR;  // this is just for warning removal
00122 }
00123                         
00124 static gePath_InterpolationType GENESISCC gePath_VKToPathInterpolation(geVKFrame_InterpolationType I)
00125 {
00126         switch (I)
00127                 {
00128                         case (VKFRAME_LINEAR):                          return GE_PATH_VK_LINEAR;
00129                         case (VKFRAME_HERMITE):                         return GE_PATH_VK_HERMITE;
00130                         case (VKFRAME_HERMITE_ZERO_DERIV):  return GE_PATH_VK_HERMITE_ZERO_DERIV;
00131                         default: assert(0);
00132                 }
00133         return GE_PATH_VK_LINEAR; // this is just for warning removal
00134 }
00135 
00136 static geQKFrame_InterpolationType GENESISCC gePath_PathToQKInterpolation(gePath_InterpolationType I)
00137 {
00138         switch (I)
00139                 {
00140                         case (GE_PATH_QK_LINEAR):       return QKFRAME_LINEAR;
00141                         case (GE_PATH_QK_SLERP):        return QKFRAME_SLERP;
00142                         case (GE_PATH_QK_SQUAD):        return QKFRAME_SQUAD;
00143                         default: assert(0);
00144                 }
00145         return QKFRAME_LINEAR;  // this is just for warning removal
00146 }
00147                         
00148 static gePath_InterpolationType GENESISCC gePath_QKToPathInterpolation(geQKFrame_InterpolationType I)
00149 {
00150         switch (I)
00151                 {
00152                         case (QKFRAME_LINEAR):  return GE_PATH_QK_LINEAR;
00153                         case (QKFRAME_SLERP):   return GE_PATH_QK_SLERP;
00154                         case (QKFRAME_SQUAD):   return GE_PATH_QK_SQUAD;
00155                         default: assert(0);
00156                 }
00157         return GE_PATH_QK_LINEAR; // this is just for warning removal
00158 }
00159 
00160 
00161 GENESISAPI void GENESISCC gePath_CreateRef( gePath *P )
00162 {
00163         assert( P != NULL );
00164         P->RefCount++;
00165 }
00166 
00167 GENESISAPI gePath *GENESISCC gePath_Create(
00168         gePath_Interpolator TranslationInterpolation,   // type of interpolation for translation channel
00169         gePath_Interpolator RotationInterpolation,      // type of interpolation for rotation channel
00170         geBoolean Looped)                               // GE_TRUE if end of path is connected to head
00171         
00172 {
00173         gePath *P;
00174 
00175         P = geRam_Allocate(sizeof(gePath));
00176 
00177         if ( P == NULL )
00178         {
00179                 geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL);
00180                 return NULL;
00181         }
00182 
00183         P->Rotation.KeyList    = NULL;
00184         P->Translation.KeyList = NULL;
00185         
00186         P->RefCount = 0;
00187         P->Dirty    = FLAG_DIRTY;
00188 
00189         if (Looped==GE_TRUE)
00190                 P->Looped = FLAG_LOOPED;
00191         else
00192                 P->Looped = 0;
00193 
00194 
00195         switch (RotationInterpolation)
00196                 {
00197                         case (GE_PATH_INTERPOLATE_LINEAR):
00198                                 P->Rotation.InterpolationType = GE_PATH_QK_LINEAR;
00199                                 break;
00200                         case (GE_PATH_INTERPOLATE_SLERP):
00201                                 P->Rotation.InterpolationType = GE_PATH_QK_SLERP; 
00202                                 break;
00203                         case (GE_PATH_INTERPOLATE_SQUAD):
00204                                 P->Rotation.InterpolationType = GE_PATH_QK_SQUAD;
00205                                 break;
00206                         default:
00207                                 assert(0);
00208                 }
00209         
00210         P->Rotation.KeyList = NULL;
00211 
00212         switch (TranslationInterpolation)
00213                 {
00214                         case (GE_PATH_INTERPOLATE_LINEAR):
00215                                 P->Translation.InterpolationType = GE_PATH_VK_LINEAR;
00216                                 break;
00217                         case (GE_PATH_INTERPOLATE_HERMITE):
00218                                 P->Translation.InterpolationType = GE_PATH_VK_HERMITE;
00219                                 break;
00220                         case (GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV):
00221                                 P->Translation.InterpolationType = GE_PATH_VK_HERMITE_ZERO_DERIV;
00222                                 break;
00223                         default:
00224                                 assert(0);
00225                 }
00226 
00227         P->Translation.KeyList = NULL;
00228 
00229         return P;
00230 }
00231 
00232 static geBoolean GENESISCC gePath_SetupRotationKeyList(gePath *P)
00233 {
00234         assert( P != NULL );
00235         switch (P->Rotation.InterpolationType)
00236                 {
00237                         case (GE_PATH_QK_LINEAR):
00238                                 P->Rotation.KeyList = geQKFrame_LinearCreate();
00239                                 break;
00240                         case (GE_PATH_QK_SLERP):
00241                                 P->Rotation.KeyList = geQKFrame_SlerpCreate();
00242                                 break;
00243                         case (GE_PATH_QK_SQUAD):
00244                                 P->Rotation.KeyList = geQKFrame_SquadCreate();
00245                                 break;
00246                         default:
00247                                 assert(0);
00248                 }
00249         if (P->Rotation.KeyList == NULL)
00250                 {
00251                         return GE_FALSE;
00252                 }
00253         return GE_TRUE; 
00254 }
00255 
00256 static geBoolean GENESISCC gePath_SetupTranslationKeyList(gePath *P)
00257 {
00258         assert( P != NULL );
00259         switch (P->Translation.InterpolationType)
00260                 {
00261                         case (GE_PATH_VK_LINEAR):
00262                                 P->Translation.KeyList = geVKFrame_LinearCreate();
00263                                 break;
00264                         case (GE_PATH_VK_HERMITE):
00265                                 P->Translation.KeyList = geVKFrame_HermiteCreate();
00266                                 break;
00267                         case (GE_PATH_VK_HERMITE_ZERO_DERIV):
00268                                 P->Translation.KeyList = geVKFrame_HermiteCreate();
00269                                 break;
00270                         default:
00271                                 assert(0);
00272                 }
00273         if (P->Translation.KeyList == NULL)
00274                 {
00275                         return GE_FALSE;
00276                 }
00277         return GE_TRUE;
00278 }
00279 
00280 GENESISAPI gePath *GENESISCC gePath_CreateCopy(const gePath *Src)
00281 {
00282         gePath *P;
00283         gePath_TimeType Time;
00284         geBoolean Looped;
00285 
00286         int i,Count;
00287         int RInterp=0;
00288         int TInterp=0;
00289 
00290         assert ( Src != NULL );
00291 
00292         switch (Src->Rotation.InterpolationType)
00293                 {
00294                         case (GE_PATH_QK_LINEAR):
00295                                 RInterp = GE_PATH_INTERPOLATE_LINEAR;
00296                                 break;
00297                         case (GE_PATH_QK_SLERP):
00298                                 RInterp = GE_PATH_INTERPOLATE_SLERP;
00299                                 break;
00300                         case (GE_PATH_QK_SQUAD):
00301                                 RInterp = GE_PATH_INTERPOLATE_SQUAD;
00302                                 break;
00303                         default:
00304                                 assert(0);
00305                 }
00306         
00307         switch (Src->Translation.InterpolationType)
00308                 {
00309                         case (GE_PATH_VK_LINEAR):
00310                                 TInterp = GE_PATH_INTERPOLATE_LINEAR;
00311                                 break;
00312                         case (GE_PATH_VK_HERMITE):
00313                                 TInterp = GE_PATH_INTERPOLATE_HERMITE;
00314                                 break;
00315                         case (GE_PATH_VK_HERMITE_ZERO_DERIV):
00316                                 TInterp = GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV;
00317                                 break;
00318                         default:
00319                                 assert(0);
00320                 }
00321         
00322         if (Src->Looped)
00323                 Looped = GE_TRUE;
00324         else
00325                 Looped = GE_FALSE;
00326 
00327         P = gePath_Create(TInterp, RInterp, Looped);    
00328         if (P == NULL)
00329                 {
00330                         geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL);
00331                         return NULL;
00332                 }
00333 
00334         {
00335                 geVec3d V;
00336                 Count = 0;
00337                 if (Src->Translation.KeyList != NULL)
00338                         {
00339                                 Count = geTKArray_NumElements(Src->Translation.KeyList);
00340                         }
00341                 if (Count>0)
00342                         {
00343                                 if (gePath_SetupTranslationKeyList(P)==GE_FALSE)
00344                                         {
00345                                                 geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL);
00346                                                 gePath_Destroy(&P);
00347                                                 return NULL;
00348                                         }
00349 
00350                                 for (i=0; i<Count; i++)
00351                                         {
00352                                                 int Index;
00353                                                 geVKFrame_Query(Src->Translation.KeyList, i, &Time, &V);
00354                                                 if (geVKFrame_Insert(&(P->Translation.KeyList), Time, &V,&Index) == GE_FALSE)
00355                                                         {
00356                                                                 geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL);
00357                                                                 gePath_Destroy(&P);
00358                                                                 return NULL;
00359                                                         }
00360                                         }
00361                         }
00362         }
00363 
00364         {
00365                 geQuaternion Q;
00366                 Count = 0;
00367                 if (Src->Rotation.KeyList != NULL)
00368                         {
00369                                 Count = geTKArray_NumElements(Src->Rotation.KeyList);
00370                         }
00371                 if (Count>0)
00372                         {
00373                                 if (gePath_SetupRotationKeyList(P)==GE_FALSE)
00374                                         {
00375                                                 geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL);
00376                                                 gePath_Destroy(&P);
00377                                                 return NULL;
00378                                         }
00379 
00380                                 for (i=0; i<Count; i++)
00381                                         {
00382                                                 int Index;
00383                                                 geQKFrame_Query(Src->Rotation.KeyList, i, &Time, &Q);
00384                                                 if (geQKFrame_Insert(&(P->Rotation.KeyList), Time, &Q, &Index) == GE_FALSE)
00385                                                         {
00386                                                                 geErrorLog_Add(ERR_PATH_CREATE_ENOMEM, NULL);
00387                                                                 gePath_Destroy(&P);
00388                                                                 return NULL;
00389                                                         }
00390                                         }
00391                         }
00392         }
00393         return P;
00394 }
00395         
00396 
00397 
00398 GENESISAPI void GENESISCC gePath_Destroy(gePath **PP)
00399 {
00400         gePath *P;
00401         
00402         assert( PP  != NULL );
00403         assert( *PP != NULL );
00404         
00405         P = *PP;
00406 
00407         if ( P->RefCount > 0)
00408                 {
00409                         P->RefCount -- ;
00410                         return;
00411                 }
00412         if ( P->Rotation.KeyList != NULL)
00413         {
00414                 geTKArray_Destroy(&(P->Rotation.KeyList));
00415                 P->Rotation.KeyList = NULL;
00416         }
00417 
00418         if ( P->Translation.KeyList != NULL)
00419         {
00420                 geTKArray_Destroy(&(P->Translation.KeyList));
00421                 P->Translation.KeyList = NULL;
00422         }
00423 
00424         geRam_Free(*PP);
00425 
00426         *PP = NULL;
00427 }
00428 
00429 
00430 static void GENESISCC gePath_Recompute(gePath *P)
00431         // Recompute any pre-computed constants for the current path.
00432 {
00433         geBoolean Looped;
00434         assert(P);
00435 
00436         P->Dirty = 0;
00437 
00438         P->Translation.LastKey1Time = 0.0f;
00439         P->Translation.LastKey2Time = -1.0f;
00440         if (P->Looped)
00441                 Looped = GE_TRUE;
00442         else
00443                 Looped = GE_FALSE;
00444 
00445         if (P->Translation.KeyList != NULL)
00446         {
00447                 if (geTKArray_NumElements(P->Translation.KeyList) > 0 )
00448                 {
00449                         P->Translation.StartTime =      geTKArray_ElementTime(P->Translation.KeyList,0);
00450                         P->Translation.EndTime   =      geTKArray_ElementTime(P->Translation.KeyList,
00451                                                                                 geTKArray_NumElements(P->Translation.KeyList) - 1);
00452                 }
00453                 if(P->Translation.InterpolationType == GE_PATH_VK_HERMITE)
00454                         geVKFrame_HermiteRecompute(Looped, GE_FALSE, P->Translation.KeyList);
00455                 else if (P->Translation.InterpolationType == GE_PATH_VK_HERMITE_ZERO_DERIV)
00456                         geVKFrame_HermiteRecompute(Looped, GE_TRUE, P->Translation.KeyList);
00457         }
00458         
00459         P->Rotation.LastKey1Time = 0.0f;
00460         P->Rotation.LastKey2Time = -1.0f;
00461 
00462         if (P->Rotation.KeyList != NULL)
00463         {
00464                 if (geTKArray_NumElements(P->Rotation.KeyList) > 0 )
00465                 {
00466                         P->Rotation.StartTime = geTKArray_ElementTime(P->Rotation.KeyList,0);
00467                         P->Rotation.EndTime   = geTKArray_ElementTime(P->Rotation.KeyList,
00468                                                                         geTKArray_NumElements(P->Rotation.KeyList) - 1);
00469                 }
00470                 if (P->Rotation.InterpolationType == GE_PATH_QK_SQUAD)
00471                         geQKFrame_SquadRecompute(Looped, P->Rotation.KeyList);
00472                 else if (P->Rotation.InterpolationType == GE_PATH_QK_SLERP)
00473                         geQKFrame_SlerpRecompute(P->Rotation.KeyList);
00474         }
00475 }       
00476 
00477 //------------------ time based keyframe operations
00478 GENESISAPI geBoolean GENESISCC gePath_InsertKeyframe(
00479         gePath *P, 
00480         int ChannelMask, 
00481         gePath_TimeType Time, 
00482         const geXForm3d *Matrix)
00483 {
00484         int VIndex;
00485         int QIndex=0;
00486         assert( P != NULL );
00487         assert( Matrix != NULL );
00488         assert( ( ChannelMask & GE_PATH_ROTATION_CHANNEL    ) ||
00489                         ( ChannelMask & GE_PATH_TRANSLATION_CHANNEL ) );
00490         
00491         if (ChannelMask & GE_PATH_ROTATION_CHANNEL)
00492         {       
00493                 geQuaternion Q;
00494                 geQuaternion_FromMatrix(Matrix, &Q);
00495                 geQuaternion_Normalize(&Q);
00496                 if (P->Rotation.KeyList==NULL)
00497                 {
00498                         if (gePath_SetupRotationKeyList(P)==GE_FALSE)
00499                                 {
00500                                         geErrorLog_Add(ERR_PATH_INSERT_R_KEYFRAME, NULL);
00501                                         return GE_FALSE;
00502                                 }
00503                 }
00504                 if (geQKFrame_Insert(&(P->Rotation.KeyList), Time, &Q, &QIndex) == GE_FALSE)
00505                 {
00506                         geErrorLog_Add(ERR_PATH_INSERT_R_KEYFRAME, NULL);
00507                         return GE_FALSE;
00508                 }
00509         }
00510 
00511         
00512         if (ChannelMask & GE_PATH_TRANSLATION_CHANNEL)
00513         {
00514                 geBoolean ErrorOccured = GE_FALSE;
00515                 if (P->Translation.KeyList == NULL)
00516                         {
00517                                 if (gePath_SetupTranslationKeyList(P)==GE_FALSE)
00518                                         {
00519                                                 geErrorLog_Add(ERR_PATH_INSERT_R_KEYFRAME, NULL);
00520                                                 ErrorOccured = GE_TRUE;
00521                                         }
00522                         }
00523                 if (ErrorOccured == GE_FALSE)
00524                         {
00525                                 if (geVKFrame_Insert( &(P->Translation.KeyList), Time, &(Matrix->Translation), &VIndex) == GE_FALSE)
00526                                         {
00527                                                 geErrorLog_Add(ERR_PATH_INSERT_T_KEYFRAME, NULL);
00528                                                 ErrorOccured = GE_TRUE;
00529                                         }
00530                         }
00531                 if (ErrorOccured != GE_FALSE)
00532                         {
00533                                 if (ChannelMask & GE_PATH_ROTATION_CHANNEL)
00534                                         {       // clean up previously inserted rotation
00535                                                 if (geTKArray_DeleteElement(&(P->Rotation.KeyList),QIndex)==GE_FALSE)
00536                                                         {
00537                                                                 geErrorLog_Add(ERR_PATH_DELETE_T_KEYFRAME, NULL);
00538                                                         }
00539                                         }
00540                                 P->Dirty = FLAG_DIRTY;
00541                                 return GE_FALSE;
00542                         }
00543         }
00544 
00545         P->Dirty = FLAG_DIRTY;
00546 
00547         return GE_TRUE;
00548 }
00549         
00550 GENESISAPI geBoolean GENESISCC gePath_DeleteKeyframe(
00551         gePath *P,
00552         int Index,
00553         int ChannelMask)
00554 {
00555         int ErrorOccured= 0;
00556 
00557         assert( P != NULL );
00558         assert( ( ChannelMask & GE_PATH_ROTATION_CHANNEL    ) ||
00559                         ( ChannelMask & GE_PATH_TRANSLATION_CHANNEL ) );
00560 
00561         if (ChannelMask & GE_PATH_ROTATION_CHANNEL)
00562         {
00563                 if (geTKArray_DeleteElement( &(P->Rotation.KeyList), Index) == GE_FALSE)
00564                 {
00565                         ErrorOccured = 1;
00566                         geErrorLog_Add(ERR_PATH_DELETE_R_KEYFRAME, NULL);
00567                 }
00568         }
00569                         
00570         if (ChannelMask & GE_PATH_TRANSLATION_CHANNEL)
00571         {
00572                 if (geTKArray_DeleteElement( &(P->Translation.KeyList), Index) == GE_FALSE)
00573                 {
00574                         ErrorOccured = 1;
00575                         geErrorLog_Add(ERR_PATH_DELETE_T_KEYFRAME, NULL);
00576                 }
00577         }
00578 
00579         P->Dirty = FLAG_DIRTY;
00580 
00581 
00582         if (ErrorOccured)
00583         {
00584                 return GE_FALSE;
00585         }
00586 
00587         return GE_TRUE;
00588 }
00589 
00590 
00591 GENESISAPI void GENESISCC gePath_GetKeyframe(
00592         const gePath *P, 
00593         int Index,                              // gets keyframe[index]
00594         int Channel,                    // for this channel
00595         gePath_TimeType *Time,  // returns the time of the keyframe
00596         geXForm3d *Matrix)              // returns the matrix of the keyframe
00597 {
00598         assert( P != NULL );
00599         assert( Index >= 0 );
00600         assert( Time != NULL );
00601         assert( Matrix != NULL );
00602 
00603         geXForm3d_SetIdentity(Matrix);
00604 
00605         switch (Channel)
00606         {
00607         case (GE_PATH_ROTATION_CHANNEL):
00608                 {
00609                         geQuaternion Q;
00610                         assert( Index < geTKArray_NumElements(P->Rotation.KeyList) );
00611                         geQKFrame_Query(P->Rotation.KeyList, Index, Time, &Q);
00612                         geQuaternion_ToMatrix(&Q, Matrix);
00613                 }
00614                 break;
00615 
00616         case (GE_PATH_TRANSLATION_CHANNEL):
00617                 {
00618                         assert( Index < geTKArray_NumElements(P->Translation.KeyList) );
00619                         geVKFrame_Query(P->Translation.KeyList, Index, Time, &(Matrix->Translation));
00620                 }
00621                 break;
00622 
00623         default:
00624                 assert(0);
00625         }
00626 }
00627 
00628 GENESISAPI geBoolean GENESISCC gePath_ModifyKeyframe(
00629         gePath *P, 
00630         int Index,                                              // keyframe[index]
00631         int ChannelMask,                                // for this channel
00632         const geXForm3d *Matrix)                // new matrix for the keyframe
00633 {
00634         assert( P != NULL );
00635         assert( Index >= 0 );
00636         assert( Matrix != NULL );
00637         assert( ( ChannelMask & GE_PATH_ROTATION_CHANNEL    ) ||
00638                         ( ChannelMask & GE_PATH_TRANSLATION_CHANNEL ) );
00639 
00640 
00641         if (ChannelMask & GE_PATH_ROTATION_CHANNEL)
00642                 {
00643                         geQuaternion Q;
00644                         assert( Index < geTKArray_NumElements(P->Rotation.KeyList) );
00645                         geQuaternion_FromMatrix(Matrix, &Q);
00646                         geQuaternion_Normalize(&Q);
00647                         geQKFrame_Modify(P->Rotation.KeyList, Index, &Q);
00648                 }
00649 
00650         if (ChannelMask & GE_PATH_TRANSLATION_CHANNEL)
00651                 {
00652                         assert( Index < geTKArray_NumElements(P->Translation.KeyList) );
00653                         geVKFrame_Modify(P->Translation.KeyList, Index, &(Matrix->Translation));
00654                 }
00655 
00656         P->Dirty = FLAG_DIRTY;
00657         return GE_TRUE;
00658 }
00659 
00660 
00661 GENESISAPI int GENESISCC gePath_GetKeyframeCount(const gePath *P, int Channel)
00662 {
00663         assert( P != NULL );
00664 
00665         switch (Channel)
00666         {
00667                 case (GE_PATH_ROTATION_CHANNEL):
00668                         if (P->Rotation.KeyList!=NULL)
00669                                 {
00670                                         return geTKArray_NumElements(P->Rotation.KeyList);
00671                                 }
00672                         else
00673                                 {
00674                                         return 0;
00675                                 }
00676                         break;
00677 
00678                 case (GE_PATH_TRANSLATION_CHANNEL):
00679                         if (P->Translation.KeyList!=NULL)
00680                                 {
00681                                         return geTKArray_NumElements(P->Translation.KeyList);
00682                                 }
00683                         else
00684                                 {
00685                                         return 0;
00686                                 }
00687                         break;
00688 
00689                 default:
00690                         assert(0);
00691         }
00692         return 0; // this is just for warning removal
00693 }
00694 
00695 GENESISAPI int GENESISCC gePath_GetKeyframeIndex(const gePath *P, int Channel, geFloat Time)
00696         // retrieves the index of the keyframe at a specific time for a specific channel
00697 {
00698         int KeyIndex;
00699         geTKArray *Array = NULL;
00700 
00701         assert ((Channel == GE_PATH_TRANSLATION_CHANNEL) ||
00702                         (Channel == GE_PATH_ROTATION_CHANNEL));
00703 
00704         switch (Channel)
00705         {
00706                 case GE_PATH_ROTATION_CHANNEL :
00707                         Array = P->Rotation.KeyList;
00708                         break;
00709 
00710                 case GE_PATH_TRANSLATION_CHANNEL :
00711                         Array = P->Translation.KeyList;
00712                         break;
00713         }
00714 
00715         // find the time in the channel's array
00716         KeyIndex = geTKArray_BSearch (Array, Time);
00717         if (KeyIndex != -1)
00718         {
00719                 // since geTKArray_BSearch will return the "closest" key,
00720                 // I need to make sure that it's exact...
00721                 if (fabs (Time - geTKArray_ElementTime (Array, KeyIndex)) > GE_TKA_TIME_TOLERANCE)
00722                 {
00723                         KeyIndex = -1;
00724                 }
00725         }
00726 
00727         return KeyIndex;
00728 }
00729 
00730 
00731 static gePath_TimeType GENESISCC gePath_AdjustTimeForLooping(
00732         geBoolean Looped,
00733         gePath_TimeType Time, 
00734         gePath_TimeType TStart, 
00735         gePath_TimeType TEnd)
00736 {
00737         if (Looped!=GE_FALSE)
00738         {
00739                 if (Time < TStart)
00740                 {
00741                         return (gePath_TimeType)fmod(Time - TStart, TEnd - TStart) + TStart + TEnd;
00742                 }
00743                 else
00744                 {
00745                         if (Time >= TEnd)
00746                         {
00747                                 if(TStart + GE_TKA_TIME_TOLERANCE > TEnd)
00748                                         return TStart;
00749 
00750                                 return (gePath_TimeType)fmod(Time - TStart, TEnd - TStart) + TStart;
00751                         }
00752                         else
00753                         {
00754                                 return Time;
00755                         }
00756                 }
00757         }
00758         else
00759         {
00760                 return Time;
00761         }
00762 }
00763 
00764 
00765 static geBoolean GENESISCC gePath_SampleChannel(
00766         const gePath_Channel *Channel,                  // channel to sample
00767         geBoolean Looped,
00768         gePath_TimeType Time, 
00769         void *Result)
00770                                 // return GE_TRUE if sample was made,
00771                                 // return GE_FALSE if no sample was made (no keyframes)
00772 {
00773         int Index1,Index2;                              // index of keyframe just before and after Time
00774         gePath_TimeType Time1, Time2;   // Times in those keyframes     
00775         gePath_TimeType T;                              // 0..1 blending factor
00776         gePath_TimeType AdjTime;                // parameter Time adjusted for looping.
00777         int Length;
00778         
00779         assert( Channel != NULL );
00780         assert( Result != NULL );
00781 
00782         if (Channel->KeyList == NULL)   
00783                 return GE_FALSE;
00784         
00785         Length = geTKArray_NumElements( Channel->KeyList );
00786                         
00787         if ( Length == 0 )
00788         {
00789                 //Interpolate(Channel,NULL,NULL,Time,Result);
00790                 return GE_FALSE;
00791         }
00792 
00793         AdjTime = gePath_AdjustTimeForLooping(Looped,Time,
00794                         Channel->StartTime,Channel->EndTime);
00795 
00796         if (    ( Channel->LastKey1Time <= AdjTime ) && 
00797                         ( AdjTime < Channel->LastKey2Time  ) )
00798         {  
00799                 Index1 = Channel->LastKey1;
00800                 Index2 = Channel->LastKey2;
00801                 Time1  = Channel->LastKey1Time;
00802                 Time2  = Channel->LastKey2Time;
00803         }
00804         else
00805         {
00806                 Index1 = geTKArray_BSearch( Channel->KeyList,
00807                                                                 AdjTime);
00808                 Index2 = Index1 + 1;
00809 
00810                 // edge conditions: if Time is off end of path's time, use end point twice
00811                 if ( Index1 < 0 )       
00812                 {
00813                         if (Looped!=GE_FALSE) 
00814                         {
00815                                 Index1 = Length -1;
00816                         }
00817                         else
00818                         {
00819                                 Index1 = 0;
00820                         }
00821                 }
00822                 if ( Index2 >= Length )
00823                 {
00824                         if (Looped!=GE_FALSE)
00825                         {
00826                                 Index2 = 0;
00827                         }
00828                         else
00829                         {
00830                                 Index2 = Length - 1;
00831                         }
00832                 }
00833                 ((gePath_Channel *)Channel)->LastKey1 = Index1;
00834                 ((gePath_Channel *)Channel)->LastKey2 = Index2;
00835                 Time1 = ((gePath_Channel *)Channel)->LastKey1Time = geTKArray_ElementTime(Channel->KeyList, Index1);
00836                 Time2 = ((gePath_Channel *)Channel)->LastKey2Time = geTKArray_ElementTime(Channel->KeyList, Index2);
00837         }
00838         
00839         if (Index1 == Index2)
00840                 T=0.0f;                 // Time2 == Time1 !
00841         else
00842                 T = (AdjTime-Time1) / (Time2 - Time1);
00843         
00844         gePath_Statics.InterpolationTable[Channel->InterpolationType](
00845                                 geTKArray_Element(Channel->KeyList,Index1),
00846                                 geTKArray_Element(Channel->KeyList,Index2),
00847                                 T,Result);
00848 
00849         return GE_TRUE;
00850 }
00851 
00852 
00853 GENESISAPI void GENESISCC gePath_Sample(const gePath *P, gePath_TimeType Time, geXForm3d *Matrix)
00854 {
00855         geQuaternion    Rotation;
00856         geVec3d         Translation;
00857         geBoolean Looped;
00858 
00859         assert( P != NULL );
00860         assert( Matrix != NULL );
00861 
00862 
00863         if (P->Dirty)
00864                 {
00865                         gePath_Recompute((gePath *)P);
00866                 }
00867         if (P->Looped)
00868                 Looped = GE_TRUE;
00869         else
00870                 Looped = GE_FALSE;
00871 
00872         if(gePath_SampleChannel(&(P->Rotation), Looped, Time, (void*)&Rotation) == GE_TRUE)
00873         {
00874                 geQuaternion_ToMatrix(&Rotation, Matrix);
00875         }
00876         else
00877         {
00878                 geXForm3d_SetIdentity(Matrix);
00879         }
00880 
00881         if(gePath_SampleChannel(&(P->Translation), Looped, Time, (void*)&Translation) == GE_TRUE)
00882         {
00883                 Matrix->Translation = Translation;
00884         }
00885         else
00886         {
00887                 Matrix->Translation.X = Matrix->Translation.Y = Matrix->Translation.Z = 0.0f;
00888         }
00889 
00890 }
00891 
00892 void GENESISCC gePath_SampleChannels(const gePath *P, gePath_TimeType Time, geQuaternion *Rotation, geVec3d *Translation)
00893 {
00894         geBoolean Looped;
00895         assert( P != NULL );
00896         assert( Rotation != NULL );
00897         assert( Translation != NULL );
00898 
00899         if (P->Dirty)
00900                 {
00901                         gePath_Recompute((gePath *)P);
00902                 }
00903 
00904         if (P->Looped)
00905                 Looped = GE_TRUE;
00906         else
00907                 Looped = GE_FALSE;
00908         
00909         if(gePath_SampleChannel(&(P->Rotation), Looped, Time, (void*)Rotation) == GE_FALSE)
00910         {
00911                 geQuaternion_SetNoRotation(Rotation);
00912         }
00913 
00914         if(gePath_SampleChannel(&(P->Translation), Looped, Time, (void*)Translation) == GE_FALSE)
00915         {
00916                 Translation->X  = Translation->Y = Translation->Z = 0.0f;
00917         }
00918 }
00919 
00920 
00921 GENESISAPI geBoolean GENESISCC gePath_GetTimeExtents(const gePath *P, gePath_TimeType *StartTime, gePath_TimeType *EndTime)
00922         // returns false and times are unchanged if there is no extent (no keys)
00923 {
00924         gePath_TimeType TransStart,TransEnd,RotStart,RotEnd;
00925 
00926         int RCount,TCount;
00927         assert( P != NULL );
00928         assert( StartTime != NULL );
00929         assert( EndTime != NULL );
00930         // this is a pain because each channel may have 0,1, or more keys
00931         
00932         if (P->Rotation.KeyList!=NULL)
00933                 RCount = geTKArray_NumElements( P->Rotation.KeyList );
00934         else
00935                 RCount = 0;
00936 
00937         if (P->Translation.KeyList!=NULL)
00938                 TCount = geTKArray_NumElements( P->Translation.KeyList );
00939         else
00940                 TCount = 0;
00941         
00942         if (RCount>0)
00943                 {       
00944                         RotStart = geTKArray_ElementTime(P->Rotation.KeyList, 0);
00945                         if (RCount>1)
00946                                 {
00947                                         RotEnd = geTKArray_ElementTime(P->Rotation.KeyList, RCount-1);
00948                                 }
00949                         else
00950                                 {
00951                                         RotEnd = RotStart;
00952                                 }
00953                         if (TCount>0)
00954                                 {       // Rotation and Translation keys
00955                                         TransStart = geTKArray_ElementTime(P->Translation.KeyList, 0);
00956                                         if (TCount>1)
00957                                                 {
00958                                                         TransEnd = geTKArray_ElementTime(P->Translation.KeyList,TCount-1);
00959                                                 }
00960                                         else
00961                                                 {
00962                                                         TransEnd = TransStart;
00963                                                 }
00964 
00965                                         *StartTime = min(TransStart,RotStart);
00966                                         *EndTime   = max(TransEnd,RotEnd);
00967                                 }
00968                         else
00969                                 {       // No Translation Keys
00970                                         *StartTime = RotStart;
00971                                         *EndTime   = RotEnd;
00972                                 }
00973                 }
00974         else
00975                 {  // No Rotation Keys
00976                         if (TCount>0)
00977                                 {
00978                                         *StartTime = geTKArray_ElementTime(P->Translation.KeyList, 0);
00979                                         if (TCount>1)
00980                                                 {
00981                                                         *EndTime = geTKArray_ElementTime(P->Translation.KeyList,TCount-1);
00982                                                 }
00983                                         else
00984                                                 {
00985                                                         *EndTime = *StartTime;
00986                                                 }
00987                                 }
00988                         else
00989                                 {       // No Rotation or Translation keys
00990                                         return GE_FALSE;
00991                                 }
00992                 }
00993         return GE_TRUE; 
00994 }
00995 
00996 // First uint32 of ASCII and Binary formats flags the file type.  If the value
00997 // matches the token, it's ASCII.  Binary files use this uint32 for versions
00998 // and flags.
00999 
01000 #define GE_PATH_BINARY_FILE_VERSION 0x1001
01001 static gePath *GENESISCC gePath_CreateFromBinaryFile(geVFile *F,uint32 Header);
01002 
01003 
01004 #define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL); return GE_FALSE; }
01005 
01006 #define GE_PATH_CHANNEL_ASCII_FILE_TYPE 0x4C4E4843      // 'CHNL'
01007 #define GE_PATH_CHANNEL_FILE_VERSION 0x00F0             // Restrict version to 16 bits
01008 
01009 #define GE_PATH_CHANNEL_INTERPOLATE_ID "InterpolationType"
01010 #define GE_PATH_CHANNEL_STARTTIME_ID "StartTime"
01011 #define GE_PATH_CHANNEL_ENDTIME_ID "EndTime"
01012 #define GE_PATH_CHANNEL_KEYLIST_ID "KeyList"
01013 #define GE_PATH_CHANNEL_NUM_ASCII_IDS 4 // Keep this up to date
01014 
01015 geBoolean GENESISCC gePath_ReadChannel_F0_(int ChannelMask, gePath_Channel *C, geVFile* pFile)
01016 {
01017         uint32 u, v;
01018         int NumItemsNeeded=0;
01019         int NumItemsRead = 0;
01020         #define LINE_LENGTH 256
01021         char line[LINE_LENGTH];
01022         geBoolean (GENESISCC *FrameRead)(geVFile*, void*);
01023         gePath_TimeType Time;
01024         int Interp=0;
01025         void* pElement;
01026         char    VersionString[32];
01027 
01028         assert( C != NULL );
01029         assert( pFile != NULL );
01030 
01031         // Read the format/version flag
01032         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
01033         {
01034                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01035                 return GE_FALSE;
01036         }
01037 
01038         if(u != GE_PATH_CHANNEL_ASCII_FILE_TYPE)
01039         {
01040                 geErrorLog_Add( ERR_PATH_FILE_VERSION , NULL);
01041                 return GE_FALSE;
01042         }
01043 
01044         // Read and build the version.  Then determine the number of items to read.
01045         if      (geVFile_GetS(pFile, VersionString, sizeof(VersionString)) == GE_FALSE)
01046         {
01047                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01048                 return GE_FALSE;
01049         }
01050 
01051         if      (sscanf(VersionString, "%X.%X\n", &u, &v) != 2)
01052         {
01053                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01054                 return GE_FALSE;
01055         }
01056         v |= (u << 8);
01057         if(v >= GE_PATH_CHANNEL_FILE_VERSION)
01058         {
01059                 NumItemsNeeded = GE_PATH_CHANNEL_NUM_ASCII_IDS;
01060         }
01061 
01062         // Set InterpolationType to something less than valid so the KeyList will
01063         // be assured of reading properly.
01064         C->InterpolationType = -1;
01065 
01066         // reset sample optimization bracket
01067         C->LastKey1Time = 0.0f;
01068         C->LastKey2Time = -1.0f;
01069 
01070         while(NumItemsRead < NumItemsNeeded)
01071         {
01072                 if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01073                         {                                               
01074                                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01075                                 break;           // got to read something
01076                         }
01077 
01078                 if(strnicmp(line, GE_PATH_CHANNEL_INTERPOLATE_ID, sizeof(GE_PATH_CHANNEL_INTERPOLATE_ID)-1) == 0)
01079                 {
01080                         if(sscanf(line + sizeof(GE_PATH_CHANNEL_INTERPOLATE_ID)-1, "%d", &Interp) != 1)
01081                                 {                                               
01082                                         geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01083                                         break;           
01084                                 }
01085                         NumItemsRead++;
01086                 }
01087                 else if(strnicmp(line, GE_PATH_CHANNEL_STARTTIME_ID, sizeof(GE_PATH_CHANNEL_STARTTIME_ID)-1) == 0)
01088                 {
01089                         if(sscanf(line + sizeof(GE_PATH_CHANNEL_STARTTIME_ID)-1, "%f", &C->StartTime) != 1)
01090                                 {                                               
01091                                         geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01092                                         break;           
01093                                 }
01094                         NumItemsRead++;
01095                 }
01096                 else if(strnicmp(line, GE_PATH_CHANNEL_ENDTIME_ID, sizeof(GE_PATH_CHANNEL_ENDTIME_ID)-1) == 0)
01097                 {
01098                         if(sscanf(line + sizeof(GE_PATH_CHANNEL_ENDTIME_ID)-1, "%f", &C->EndTime) != 1)
01099                                 {                                               
01100                                         geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01101                                         break;           
01102                                 }
01103                         NumItemsRead++;
01104                 }
01105                 else if(strnicmp(line, GE_PATH_CHANNEL_KEYLIST_ID, sizeof(GE_PATH_CHANNEL_KEYLIST_ID)-1) == 0)
01106                 {
01107                         assert(C->KeyList == NULL);
01108 
01109                         // v = number of elements
01110                         if(sscanf(line + sizeof(GE_PATH_CHANNEL_KEYLIST_ID)-1, "%d", &v) != 1)
01111                                 {                                               
01112                                         geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01113                                         break;           
01114                                 }
01115 
01116                         if(ChannelMask == GE_PATH_ROTATION_CHANNEL)
01117                         {
01118                                 switch(Interp)
01119                                 {
01120                                 case GE_PATH_INTERPOLATE_LINEAR:
01121                                         C->KeyList = geQKFrame_LinearCreate();
01122                                         C->InterpolationType = GE_PATH_QK_LINEAR;
01123                                         FrameRead = geQKFrame_LinearRead;
01124                                         break;
01125 
01126                                 case GE_PATH_INTERPOLATE_SLERP:
01127                                         C->KeyList = geQKFrame_SlerpCreate();
01128                                         C->InterpolationType = GE_PATH_QK_SLERP;
01129                                         FrameRead = geQKFrame_SlerpRead;
01130                                         break;
01131 
01132                                 case GE_PATH_INTERPOLATE_SQUAD:
01133                                         C->KeyList = geQKFrame_SquadCreate();
01134                                         C->InterpolationType = GE_PATH_QK_SQUAD;
01135                                         FrameRead = geQKFrame_SquadRead;
01136                                         break;
01137 
01138                                 default:
01139                                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01140                                         return GE_FALSE;
01141                                 }
01142                         }
01143                         else
01144                         {
01145                                 assert(ChannelMask == GE_PATH_TRANSLATION_CHANNEL);
01146 
01147                                 switch(Interp)
01148                                 {
01149                                 case GE_PATH_INTERPOLATE_LINEAR:
01150                                         C->KeyList = geVKFrame_LinearCreate();
01151                                         C->InterpolationType = GE_PATH_VK_LINEAR;
01152                                         FrameRead = geVKFrame_LinearRead;
01153                                         break;
01154 
01155                                 case GE_PATH_INTERPOLATE_HERMITE:
01156                                         C->KeyList = geVKFrame_HermiteCreate();
01157                                         C->InterpolationType = GE_PATH_VK_HERMITE;
01158                                         FrameRead = geVKFrame_HermiteRead;
01159                                         break;
01160 
01161                                 case GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV:
01162                                         C->KeyList = geVKFrame_HermiteCreate();
01163                                         C->InterpolationType = GE_PATH_VK_HERMITE_ZERO_DERIV;
01164                                         FrameRead = geVKFrame_HermiteRead;
01165                                         break;
01166 
01167                                 default:
01168                                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01169                                         return GE_FALSE;
01170                                 }
01171                         }
01172 
01173                         while( v > 0 )
01174                         {
01175                                 char    TimeString[32];
01176                                 v--;
01177 
01178                                 if(geVFile_GetS(pFile, TimeString, sizeof(TimeString)) == GE_FALSE)
01179                                         {                                               
01180                                                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01181                                                 break;           
01182                                         }
01183                                 if(sscanf(TimeString, "%f ", &Time) != 1)
01184                                         {                                               
01185                                                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01186                                                 break;           
01187                                         }
01188 
01189                                 {
01190                                         int NewlyAddedElement;  // u = newly added element
01191                                         if(geTKArray_Insert(&C->KeyList, Time, &NewlyAddedElement) == GE_FALSE)
01192                                                 break;
01193                                         pElement = geTKArray_Element(C->KeyList, NewlyAddedElement);
01194                                 }
01195                                 if(FrameRead(pFile, pElement) == GE_FALSE)
01196                                         break;
01197                         }
01198 
01199                         if( v > 0 )
01200                         {
01201                                 // must have aborted early
01202                                 geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01203                                 break;
01204                         }
01205 
01206                         NumItemsRead++;
01207                 }
01208                 else
01209                 {
01210                         // Bad news, unknown line, kill the loop
01211                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01212                         break;
01213                 }
01214         }
01215         if (NumItemsNeeded == NumItemsRead)
01216                 {
01217                         return GE_TRUE;
01218                 }
01219         else
01220                 {
01221                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01222                         return GE_FALSE;
01223                 }
01224 }
01225 
01226 
01227 #define GE_PATH_ASCII_FILE_TYPE 0x48544150      // 'PATH'
01228 #define GE_PATH_FILE_VERSION0 0x00F0            // Restrict version to 16 bits
01229 #define GE_PATH_FILE_VERSION1 0x00F1            // Restrict version to 16 bits
01230 #define GE_PATH_FILE_VERSION  0x00F2            // Restrict version to 16 bits
01231 
01232 #define GE_PATH_ROTATION_ID "Rotation"
01233 #define GE_PATH_TRANSLATION_ID "Translation"
01234 #define GE_PATH_LOOPED_ID "Looped"
01235 #define GE_PATH_NUM_ASCII_IDS 2 // Keep this up to date
01236 
01237 #define EXIT_ERROR { gePath_Destroy(&P); geErrorLog_Add( ERR_PATH_FILE_READ , NULL); return NULL; }
01238 
01239 gePath* GENESISCC gePath_CreateFromFile_F0_(geVFile* pFile)
01240 {
01241         gePath* P;
01242         int flag;
01243                 
01244         #define LINE_LENGTH 256
01245         char line[LINE_LENGTH];
01246 
01247         assert( pFile != NULL );
01248         
01249         P = gePath_Create(0, 0, GE_FALSE);
01250         if( P == NULL )
01251                 {
01252                         return NULL;    // error logged already in gePath_Create
01253                 }
01254 
01255         P->Translation.InterpolationType = 0;
01256         P->Rotation.InterpolationType    = 0;
01257 
01258         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01259                 EXIT_ERROR
01260         if(strnicmp(line, GE_PATH_LOOPED_ID, sizeof(GE_PATH_LOOPED_ID)-1) != 0)
01261                 EXIT_ERROR
01262 
01263         if(sscanf(line + sizeof(GE_PATH_LOOPED_ID)-1, "%d", &flag) != 1)
01264                 EXIT_ERROR
01265         
01266         if (flag == GE_TRUE)
01267                 {
01268                         P->Looped = FLAG_LOOPED;
01269                 }
01270 
01271         if(!geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01272                 EXIT_ERROR
01273         if(strnicmp(line, GE_PATH_ROTATION_ID, sizeof(GE_PATH_ROTATION_ID)-1) != 0)
01274                 EXIT_ERROR
01275 
01276         if(sscanf(line + sizeof(GE_PATH_ROTATION_ID)-1, "%d", &flag) != 1)
01277                 EXIT_ERROR
01278         if (flag!=GE_FALSE)
01279                 {
01280                         if(!gePath_ReadChannel_F0_(GE_PATH_ROTATION_CHANNEL, &P->Rotation, pFile))
01281                                 EXIT_ERROR
01282                 }
01283         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01284                 EXIT_ERROR
01285         if(strnicmp(line, GE_PATH_TRANSLATION_ID, sizeof(GE_PATH_TRANSLATION_ID)-1) != 0)
01286                 EXIT_ERROR
01287         if(sscanf(line + sizeof(GE_PATH_TRANSLATION_ID)-1, "%d", &flag) != 1)
01288                 EXIT_ERROR
01289                                         
01290         if (flag!=GE_FALSE)
01291                 if(!gePath_ReadChannel_F0_(GE_PATH_TRANSLATION_CHANNEL, &P->Translation, pFile))
01292                         EXIT_ERROR
01293         
01294         P->Dirty = FLAG_DIRTY;
01295         return P;
01296 }
01297 
01298 GENESISAPI gePath* GENESISCC gePath_CreateFromFile(geVFile* pFile)
01299 {
01300         uint32 u, v, flag;
01301         int Interp,Loop;
01302         gePath* P;
01303         #define LINE_LENGTH 256
01304         char line[LINE_LENGTH];
01305 
01306         assert( pFile != NULL );
01307         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
01308         {
01309                 geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01310                 return NULL;
01311         }
01312 
01313         if ( (u>>16) == GE_PATH_BINARY_FILE_VERSION)
01314                 return gePath_CreateFromBinaryFile(pFile,u);
01315                 
01316                 
01317         if(u != GE_PATH_ASCII_FILE_TYPE)
01318                 {
01319                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01320                         return NULL;
01321                 }
01322                 
01323         // Read the version.
01324         if      (geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01325                 {
01326                         geErrorLog_Add( ERR_PATH_FILE_READ , NULL);
01327                         return NULL;
01328                 }
01329         if      (sscanf(line, "%X.%X\n", &u, &v) != 2)
01330                 {
01331                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01332                         return NULL;
01333                 }
01334         v |= (u << 8);
01335         if(v == GE_PATH_FILE_VERSION0)
01336                 return gePath_CreateFromFile_F0_(pFile);
01337         if (! ((v == GE_PATH_FILE_VERSION1) || (v== GE_PATH_FILE_VERSION)) )
01338                 {
01339                         geErrorLog_Add( ERR_PATH_FILE_PARSE , NULL);
01340                         return NULL;
01341                 }
01342 
01343         P = gePath_Create(0, 0, GE_FALSE);
01344         if( P == NULL )
01345                 {
01346                         return NULL;    // error logged already in gePath_Create
01347                 }
01348 
01349         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01350                 EXIT_ERROR
01351         if(strnicmp(line, GE_PATH_ROTATION_ID, sizeof(GE_PATH_ROTATION_ID)-1) != 0)
01352                 EXIT_ERROR
01353         if (v==GE_PATH_FILE_VERSION1)
01354                 {
01355                         P->Rotation.InterpolationType    = 0;
01356                         if(sscanf(line + sizeof(GE_PATH_ROTATION_ID)-1, "%d", &flag) != 1)
01357                                 EXIT_ERROR
01358                 }
01359         else
01360                 {
01361                         if (v==GE_PATH_FILE_VERSION)
01362                                 {
01363                                         if(sscanf(line + sizeof(GE_PATH_ROTATION_ID)-1, "%d %d", &flag, &(P->Rotation.InterpolationType)) != 2)
01364                                                 EXIT_ERROR
01365                                 }
01366                         else
01367                                 EXIT_ERROR
01368                 }
01369         if (flag!=GE_FALSE)
01370                 {
01371                         P->Rotation.KeyList = geQKFrame_CreateFromFile(pFile,&Interp,&Loop);
01372                         if (P->Rotation.KeyList == NULL)
01373                                 EXIT_ERROR
01374                         P->Rotation.InterpolationType = gePath_QKToPathInterpolation(Interp);
01375                         if (Loop)
01376                                 P->Looped = FLAG_LOOPED;
01377                 }
01378 
01379         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01380                 EXIT_ERROR
01381         if(strnicmp(line, GE_PATH_TRANSLATION_ID, sizeof(GE_PATH_TRANSLATION_ID)-1) != 0)
01382                 EXIT_ERROR
01383         if (v==GE_PATH_FILE_VERSION1)
01384                 {
01385                         P->Translation.InterpolationType = 0;
01386                         if(sscanf(line + sizeof(GE_PATH_TRANSLATION_ID)-1, "%d", &flag) != 1)
01387                                 EXIT_ERROR
01388                 }
01389         else
01390                 {
01391                         if (v==GE_PATH_FILE_VERSION)
01392                                 {
01393                                         if(sscanf(line + sizeof(GE_PATH_TRANSLATION_ID)-1, "%d %d", &flag, &(P->Translation.InterpolationType)) != 2)
01394                                                 EXIT_ERROR
01395                                 }
01396                         else
01397                                 EXIT_ERROR
01398                 }
01399                                         
01400         if (flag!=GE_FALSE)
01401                 {
01402                         P->Translation.KeyList = geVKFrame_CreateFromFile(pFile,&Interp,&Loop);
01403                         if (P->Translation.KeyList == NULL)
01404                                 EXIT_ERROR
01405                         P->Translation.InterpolationType = gePath_VKToPathInterpolation(Interp);
01406                         if (Loop)
01407                                 P->Looped = FLAG_LOOPED;
01408                 }
01409 
01410         P->Dirty = FLAG_DIRTY;
01411         return P;
01412 }
01413 
01414 GENESISAPI geBoolean GENESISCC gePath_WriteToFile(const gePath *P,geVFile *pFile)
01415 {
01416         uint32 u;
01417         int Looped=0;
01418 
01419         assert( P != NULL );
01420         assert( pFile != NULL );
01421 
01422         if (P->Dirty)
01423                 gePath_Recompute((gePath *)P);
01424 
01425         // Write the format flag
01426         u = GE_PATH_ASCII_FILE_TYPE;
01427         if(geVFile_Write(pFile, &u,sizeof(u)) == GE_FALSE)
01428         {
01429                 geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL);
01430                 return GE_FALSE;
01431         }
01432 
01433         // Write the version
01434         if      (geVFile_Printf(pFile, " %X.%.2X\n", (GE_PATH_FILE_VERSION & 0xFF00) >> 8, 
01435                                                                         GE_PATH_FILE_VERSION & 0x00FF) == GE_FALSE)
01436                 {
01437                         geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL);
01438                         return GE_FALSE;
01439                 }
01440 
01441         {
01442                 int flag;
01443                 flag = GE_FALSE;
01444 
01445                 if (P->Rotation.KeyList != NULL)
01446                         {
01447                                 if (geTKArray_NumElements(P->Rotation.KeyList)>0)
01448                                         {
01449                                                 flag = GE_TRUE;
01450                                         }
01451                         }
01452                 if      (geVFile_Printf(pFile,
01453                                                   "%s %d %d\n",
01454                                                   GE_PATH_ROTATION_ID,
01455                                                   flag,
01456                                                   P->Rotation.InterpolationType) == GE_FALSE)
01457                         {
01458                                 geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL);
01459                                 return GE_FALSE;
01460                         }
01461 
01462                 if (P->Looped)
01463                         Looped = 1;
01464 
01465                 if (flag!=GE_FALSE)
01466                         if (geQKFrame_WriteToFile( pFile, P->Rotation.KeyList, 
01467                                                                                 gePath_PathToQKInterpolation(P->Rotation.InterpolationType),
01468                                                                                 Looped)==GE_FALSE)
01469                                 {
01470                                         return GE_FALSE;
01471                                 }
01472                 
01473                 flag = GE_FALSE;
01474                 if (P->Translation.KeyList != NULL)
01475                         {
01476                                 if (geTKArray_NumElements(P->Translation.KeyList)>0)
01477                                         {
01478                                                 flag = GE_TRUE;
01479                                         }
01480                         }
01481                 if      (geVFile_Printf(pFile,
01482                                                   "%s %d %d\n",
01483                                                   GE_PATH_TRANSLATION_ID,
01484                                                   flag,
01485                                                   P->Translation.InterpolationType) == GE_FALSE)
01486                         {
01487                                 geErrorLog_Add( ERR_PATH_FILE_WRITE , NULL);
01488                                 return GE_FALSE;
01489                         }
01490 
01491                 if (flag!=GE_FALSE)
01492                         if (geVKFrame_WriteToFile( pFile, P->Translation.KeyList, 
01493                                                                                 gePath_PathToVKInterpolation(P->Translation.InterpolationType),
01494                                                                                 Looped)==GE_FALSE)
01495                                 {
01496                                         return GE_FALSE;
01497                                 }
01498         }
01499                 
01500                         
01501         return GE_TRUE;
01502 }
01503 
01504 /*
01505         Binary file header:
01506          13 bit version id, 8 bit Rotation InterpolationType,
01507          8 bit Translation InterpolationType, 1 bits for looped flag,
01508          1 bit for translation keys exist, 1 bit for rotation keys exist
01509 */
01510 #define GE_PATH_MAX_INT_TYPE_COUNT      (127)           // 7 bits 
01511 #define GE_PATH_TRANS_SHIFT_INTO_HEADER (9)                     // 7 bits shifted into bits 9..15
01512 #define GE_PATH_ROT_SHIFT_INTO_HEADER   (2)                     // 7 bits shifted into bits 2..8
01513 
01514 GENESISAPI geBoolean GENESISCC gePath_WriteToBinaryFile(const gePath *P, geVFile *F)
01515 {
01516         uint32 Header;
01517         int R,T,Looped;
01518 
01519         assert( F != NULL );
01520         assert( P != NULL );
01521         assert( GE_PATH_BINARY_FILE_VERSION < 0xFFFF );
01522 
01523         R=T=0;
01524 
01525         if (P->Rotation.KeyList != NULL)
01526                 {
01527                         if (geTKArray_NumElements(P->Rotation.KeyList)>0)
01528                                 {
01529                                         R = GE_TRUE;
01530                                 }
01531                 }
01532                                 
01533         if (P->Translation.KeyList != NULL)
01534                 {
01535                         if (geTKArray_NumElements(P->Translation.KeyList)>0)
01536                                 {
01537                                         T = GE_TRUE;
01538                                 }
01539                 }
01540 
01541         if (P->Looped)
01542                 Looped = 1;
01543         else
01544                 Looped = 0;
01545         assert( P->Translation.InterpolationType <= GE_PATH_MAX_INT_TYPE_COUNT);        
01546         assert( P->Rotation.InterpolationType <= GE_PATH_MAX_INT_TYPE_COUNT);           
01547 
01548         Header = 
01549                 (GE_PATH_BINARY_FILE_VERSION << 16) |
01550                 (T<<1)  | 
01551                 (R)     | 
01552                 (P->Translation.InterpolationType << GE_PATH_TRANS_SHIFT_INTO_HEADER) | 
01553                 (P->Rotation.InterpolationType    << GE_PATH_ROT_SHIFT_INTO_HEADER  );
01554 
01555         if      (geVFile_Write(F, &Header,sizeof(uint32)) == GE_FALSE)
01556                 {
01557                         geErrorLog_AddString( -1 ,"Failure to write Path Binary File Header", NULL);
01558                         return GE_FALSE;
01559                 }
01560 
01561         if (T==1)
01562                 {
01563                         if (geVKFrame_WriteToBinaryFile( F, P->Translation.KeyList, 
01564                                                                                 gePath_PathToVKInterpolation(P->Translation.InterpolationType),
01565                                                                                 Looped)==GE_FALSE)
01566                                 {
01567                                         geErrorLog_AddString( -1 ,"Failure to write Path data", NULL);
01568                                         return GE_FALSE;
01569                                 }
01570                 }
01571         if (R==1)
01572                 {
01573                         if (geQKFrame_WriteToBinaryFile( F, P->Rotation.KeyList, 
01574                                                                                 gePath_PathToQKInterpolation(P->Rotation.InterpolationType),
01575                                                                                 Looped)==GE_FALSE)
01576                                 {
01577                                         geErrorLog_AddString( -1 ,"Failure to write Path data", NULL);
01578                                         return GE_FALSE;
01579                                 }
01580                 }
01581         
01582         return GE_TRUE;
01583 }
01584 
01585 
01586 
01587 static gePath * GENESISCC gePath_CreateFromBinaryFile(geVFile *F,uint32 Header)
01588 {
01589         gePath *P;
01590         int Interp,Looping;
01591 
01592         assert( F != NULL );
01593 
01594         if ((Header>>16) != GE_PATH_BINARY_FILE_VERSION)
01595                 {
01596                         geErrorLog_AddString( -1, "Bad path binary file version" , NULL);
01597                         return NULL;
01598                 }
01599 
01600         P = geRam_Allocate(sizeof(gePath));
01601         P->Translation.KeyList = NULL;
01602         P->Rotation.KeyList = NULL;
01603         if (P == NULL)
01604                 {
01605                         geErrorLog_AddString( -1, "Failure to allocate memory for path" , NULL);
01606                         return NULL;
01607                 }
01608         
01609         P->Translation.InterpolationType = (Header >> GE_PATH_TRANS_SHIFT_INTO_HEADER) & GE_PATH_MAX_INT_TYPE_COUNT;
01610         P->Rotation.InterpolationType    = (Header >> GE_PATH_ROT_SHIFT_INTO_HEADER) & GE_PATH_MAX_INT_TYPE_COUNT;
01611         // this will be replaced by the path reader (if the path has keys)
01612 
01613         P->Translation.LastKey1Time = 0.0f;
01614         P->Translation.LastKey2Time = -1.0f;
01615 
01616         P->Rotation.LastKey1Time = 0.0f;
01617         P->Rotation.LastKey2Time = -1.0f;
01618         P-> Dirty    = 0;
01619         P-> Looped   = 0;
01620         P-> RefCount = 0;
01621 
01622         if ((Header >> 1) & 0x1)
01623                 {
01624                         P->Translation.KeyList = geVKFrame_CreateFromBinaryFile(F,&Interp,&Looping);
01625                         if (P->Translation.KeyList == NULL)
01626                                 {
01627                                         geErrorLog_AddString( -1, "Failure to read translation keys" , NULL);
01628                                         geRam_Free(P);
01629                                         return NULL;
01630                                 }
01631                         P->Translation.InterpolationType = gePath_VKToPathInterpolation(Interp);
01632                         if( Looping != 0 )
01633                                 P->Looped = FLAG_LOOPED;
01634                 }
01635 
01636         if (Header & 0x1)
01637                 {
01638                         P->Rotation.KeyList = geQKFrame_CreateFromBinaryFile(F,&Interp,&Looping);
01639                         if (P->Rotation.KeyList == NULL)
01640                                 {
01641                                         geErrorLog_AddString( -1, "Failure to read rotation keys" , NULL);
01642                                         if (P->Translation.KeyList != NULL)
01643                                                 {
01644                                                         geTKArray_Destroy(&P->Translation.KeyList);
01645                                                 }
01646                                         geRam_Free(P);
01647                                         return NULL;
01648                                 }
01649                         P->Rotation.InterpolationType = gePath_QKToPathInterpolation(Interp);
01650                         if( Looping != 0 )
01651                                 P->Looped = FLAG_LOOPED;
01652 
01653                 }
01654         P->Dirty = FLAG_DIRTY;
01655         return P;
01656 }
01657                 

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