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

motion.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  MOTION.C                                                                            */
00003 /*                                                                                      */
00004 /*  Author: Mike Sandige                                                                    */
00005 /*  Description: Motion 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 /*      motion.c
00023 
00024         This object is a list of (named) gePath objects, 
00025         and an associated event list 
00026 
00027 */
00028  
00029 #include <assert.h>
00030 #include <string.h>             // strcmp, strnicmp
00031 
00032 #include "basetype.h"
00033 #include "ram.h"
00034 #include "errorlog.h"
00035 #include "motion.h"
00036 #include "tkevents.h"
00037 #include "StrBlock.h"
00038 
00039 #pragma warning(disable : 4201)         // we're using nameless structures
00040 
00041 #define gePath_TimeType geFloat
00042 
00043 #define MIN(aa,bb)  (( (aa)>(bb) ) ? (bb) : (aa) )
00044 #define MAX(aa,bb)  (( (aa)>(bb) ) ? (aa) : (bb) )
00045 
00046 typedef enum { MOTION_NODE_UNDECIDED, MOTION_NODE_BRANCH, MOTION_NODE_LEAF } geMotion_NodeType;
00047 
00048 #define MOTION_BLEND_PART_OF_TRANSFORM(TForm)  ((TForm).Translation.X)                                          
00049 #define MOTION_BLEND_PART_OF_VECTOR(Vec)  ((Vec).X)                                             
00050 
00051 
00052 typedef struct geMotion_Leaf
00053 {
00054         int                     PathCount;              
00055         int32           NameChecksum;   // checksum based on names and list order
00056         geTKEvents *Events;
00057         geStrBlock *NameArray;
00058         gePath    **PathArray;
00059 } geMotion_Leaf;
00060 
00061 
00062 typedef struct geMotion_Mixer
00063 {
00064         geFloat   TimeScale;            // multipler for time
00065         geFloat   TimeOffset;           // already scaled.
00066         gePath   *Blend;                        // path used to interpolate blending amounts. 
00067         geXForm3d Transform;            // base transform for this motion (if TransformUsed==GE_TRUE)
00068         geBoolean TransformUsed;        // GE_FALSE if there is no base transform.
00069         geMotion *Motion;                       
00070 } geMotion_Mixer;
00071 
00072 typedef struct geMotion_Branch
00073 {
00074         int                             MixerCount;
00075         int                             CurrentEventIterator;
00076         geMotion_Mixer *MixerArray;
00077 } geMotion_Branch;
00078 
00079 
00080 typedef struct geMotion
00081 {
00082         char                     *Name;
00083         int                               CloneCount;
00084         geBoolean                 MaintainNames;                
00085         geMotion_NodeType NodeType;
00086         union 
00087                 {
00088                         geMotion_Leaf   Leaf;
00089                         geMotion_Branch Branch;
00090                 };
00091         geMotion *SanityCheck;
00092 } geMotion;
00093 
00094 
00095 GENESISAPI geBoolean GENESISCC geMotion_IsValid(const geMotion *M)
00096 {
00097         if (M == NULL)
00098                 return GE_FALSE;
00099         if (M->SanityCheck!=M)
00100                 return GE_FALSE;
00101         return GE_TRUE;
00102 }
00103 
00104 GENESISAPI geBoolean GENESISCC geMotion_SetName(geMotion *M, const char *Name)
00105 {
00106         char *NewName;
00107 
00108         assert( M != NULL );
00109         assert( geMotion_IsValid(M) != GE_FALSE );
00110 
00111         NewName = geRam_Allocate( strlen(Name)+1 );
00112         if (NewName == NULL )
00113                 {
00114                         geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL);
00115                         return GE_FALSE;
00116                 }
00117         if (M->Name!=NULL)
00118                 {
00119                         geRam_Free(M->Name);
00120                 }
00121         M->Name = NewName;
00122         strcpy(M->Name, Name);
00123         return GE_TRUE;
00124 }
00125 
00126 GENESISAPI const char * GENESISCC geMotion_GetName(const geMotion *M)
00127 {
00128         assert( M != NULL );
00129         assert( geMotion_IsValid(M) != GE_FALSE );
00130         return M->Name;
00131 }
00132                 
00133 static geBoolean GENESISCC geMotion_InitNodeAsLeaf(geMotion *M,geBoolean SetupStringBlock)
00134 {
00135         assert( M != NULL );
00136         assert( geMotion_IsValid(M) != GE_FALSE );
00137         assert( M->NodeType == MOTION_NODE_UNDECIDED );
00138 
00139         M->NodeType = MOTION_NODE_LEAF;
00140         
00141         M->Leaf.PathCount     = 0;
00142         M->Leaf.Events        = NULL;
00143         M->Leaf.PathArray     = NULL;
00144         M->Leaf.NameChecksum  = 0;
00145         if ((M->MaintainNames != GE_FALSE) && (SetupStringBlock!=GE_FALSE))
00146                 {
00147                         M->Leaf.NameArray = geStrBlock_Create();
00148                         if (M->Leaf.NameArray == NULL)  
00149                                 {
00150                                         geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL);
00151                                         return GE_FALSE;
00152                                 }
00153                 }
00154         else
00155                 {
00156                         M->Leaf.NameArray  = NULL;
00157                 }
00158         return GE_TRUE;
00159 }
00160 
00161 static geBoolean GENESISCC geMotion_InitNodeAsBranch(geMotion *M)
00162 {
00163         assert( M != NULL );
00164         assert( geMotion_IsValid(M) != GE_FALSE );
00165         assert( M->NodeType == MOTION_NODE_UNDECIDED );
00166 
00167         M->NodeType = MOTION_NODE_BRANCH;
00168         
00169         M->Branch.MixerCount           = 0;
00170         M->Branch.CurrentEventIterator = 0;
00171         M->Branch.MixerArray           = NULL;
00172         return GE_TRUE;
00173 }
00174 
00175 
00176 GENESISAPI geMotion * GENESISCC geMotion_Create(geBoolean WithNames)
00177 {
00178         geMotion *M;
00179         assert( (WithNames==GE_TRUE) || (WithNames==GE_FALSE) );
00180 
00181         M = GE_RAM_ALLOCATE_STRUCT(geMotion);
00182 
00183         if ( M == NULL )
00184                 {
00185                         geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL);
00186                         return NULL;
00187                 }
00188 
00189         M->Name          = NULL;
00190         M->CloneCount    = 0;
00191         M->MaintainNames = WithNames;
00192         M->NodeType      = MOTION_NODE_UNDECIDED;
00193         M->SanityCheck   = M;
00194         return M;
00195 }
00196 
00197 
00198 GENESISAPI geBoolean GENESISCC geMotion_RemoveNames(geMotion *M)
00199 {
00200         assert( M != NULL );
00201         assert( geMotion_IsValid(M) != GE_FALSE );
00202 
00203         if (M->CloneCount > 0)
00204                 {
00205                         geErrorLog_AddString(-1,"Can't remove names from a cloned motion.", NULL);
00206                         return GE_FALSE;
00207                 }
00208 
00209         switch (M->NodeType)
00210                 {
00211                         case (MOTION_NODE_UNDECIDED):
00212                                 break;
00213                         case (MOTION_NODE_BRANCH):
00214                                 geErrorLog_AddString(-1,"Can't remove names from a compound motion.", NULL);
00215                                 return GE_FALSE;
00216                                 break;
00217                         case (MOTION_NODE_LEAF):
00218                                 assert( M->Leaf.PathCount >= 0 );
00219                                 
00220                                 if ( M->Leaf.NameArray != NULL )
00221                                         {       
00222                                                 geStrBlock_Destroy(&(M->Leaf.NameArray));
00223                                         }
00224                                 M->Leaf.NameArray = NULL;
00225                                 break;
00226                         default:
00227                                 assert(0);
00228                 }
00229 
00230         M->MaintainNames = GE_FALSE;
00231         return GE_TRUE;
00232 }
00233 
00234 
00235 
00236 GENESISAPI void GENESISCC geMotion_Destroy(geMotion **PM)
00237 {
00238         int i;
00239         geMotion *M;
00240         
00241         assert(PM   != NULL );
00242         assert(*PM  != NULL );
00243         M = *PM;
00244         assert( geMotion_IsValid(M) != GE_FALSE );
00245 
00246         if (M->CloneCount > 0 )
00247                 {
00248                         M->CloneCount--;
00249                         return;
00250                 }
00251 
00252         if (M->Name != NULL)
00253                 {
00254                         geRam_Free(M->Name);
00255                         M->Name = NULL;
00256                 }
00257 
00258         switch (M->NodeType)
00259                 {
00260                         case (MOTION_NODE_UNDECIDED):
00261                                 break;
00262                         case (MOTION_NODE_BRANCH):
00263                                 for (i=0; i<M->Branch.MixerCount; i++)
00264                                         {
00265                                                 assert( M->Branch.MixerArray[i].Motion != NULL );
00266                                                 geMotion_Destroy( &(M->Branch.MixerArray[i].Motion));
00267                                                 M->Branch.MixerArray[i].Motion = NULL;
00268 
00269                                                 if (M->Branch.MixerArray[i].Blend != NULL )
00270                                                         {
00271                                                                 gePath_Destroy( &(M->Branch.MixerArray[i].Blend));
00272                                                                 M->Branch.MixerArray[i].Blend = NULL;
00273                                                         }
00274                                                 
00275                                         }
00276                                 if (M->Branch.MixerArray != NULL)
00277                                         {
00278                                                 geRam_Free(M->Branch.MixerArray);
00279                                                 M->Branch.MixerArray = NULL;
00280                                         }
00281                                 M->Branch.MixerCount = 0;
00282                                 M->Branch.CurrentEventIterator = 0;
00283                                 break;
00284                         case (MOTION_NODE_LEAF):
00285                                 if (M->MaintainNames == GE_TRUE)
00286                                         {       
00287                                                 geBoolean Test= geMotion_RemoveNames(M);
00288                                                 assert( Test != GE_FALSE );
00289                                                 Test;
00290                                         }
00291                                 for (i=0; i< M->Leaf.PathCount; i++)
00292                                         {
00293                                                 assert( M->Leaf.PathArray[i] );
00294                                                 gePath_Destroy( &( M->Leaf.PathArray[i] ) );
00295                                                 M->Leaf.PathArray[i] = NULL;
00296                                         }
00297                                 if (M->Leaf.PathArray!=NULL)
00298                                         {
00299                                                 geRam_Free(M->Leaf.PathArray);
00300                                                 M->Leaf.PathArray = NULL;
00301                                         }
00302                                 M->Leaf.PathCount = 0;
00303                                 if ( M->Leaf.Events != NULL )
00304                                         {
00305                                                 geTKEvents_Destroy( &(M->Leaf.Events) );
00306                                         }
00307                                 break;
00308                         default:
00309                                 assert(0);
00310                 }
00311         M->NodeType = MOTION_NODE_UNDECIDED;
00312         geRam_Free( *PM );
00313         *PM = NULL;
00314 }
00315 
00316 GENESISAPI geBoolean GENESISCC geMotion_AddPath(geMotion *M,
00317         gePath *P,const char *Name,int *PathIndex)
00318 {
00319         int PathCount;
00320         assert( M != NULL );
00321         assert( geMotion_IsValid(M) != GE_FALSE );
00322 
00323         switch (M->NodeType)
00324                 {
00325                         case (MOTION_NODE_UNDECIDED):
00326                                 if (geMotion_InitNodeAsLeaf(M,GE_TRUE)==GE_FALSE)
00327                                         {
00328                                                 geErrorLog_Add(-1, NULL);
00329                                                 return GE_FALSE;
00330                                         }
00331                                 break;
00332                         case (MOTION_NODE_BRANCH):
00333                                 geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL);        //FIXME!
00334                                 return GE_FALSE;
00335                         case (MOTION_NODE_LEAF):
00336                                 break;
00337                         default:
00338                                 assert(0);
00339                 }
00340 
00341         assert( M->Leaf.PathCount >= 0 );
00342 
00343         if (Name!=NULL)
00344                 {
00345                         if (geMotion_GetPathNamed( M, Name) != NULL )
00346                                 {
00347                                         geErrorLog_Add(ERR_MOTION_ADDPATH_BAD_NAME, NULL);
00348                                         return GE_FALSE;
00349                                 }
00350                 }
00351 
00352         PathCount = M->Leaf.PathCount;
00353 
00354         {
00355                 gePath **NewPathArray;
00356 
00357                 NewPathArray = geRam_Realloc(M->Leaf.PathArray, (1+PathCount) * sizeof(gePath*) );
00358 
00359                 if ( NewPathArray == NULL )
00360                         {       
00361                                 geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL);
00362                                 return GE_FALSE;
00363                         }
00364                 M->Leaf.PathArray = NewPathArray;
00365         }
00366 
00367         M->Leaf.PathArray[PathCount] = P;
00368 
00369         if ( M->MaintainNames == GE_TRUE )
00370                 {
00371                         
00372                         assert (M->Leaf.NameArray != NULL);
00373                         if (geStrBlock_Append(&(M->Leaf.NameArray),Name)==GE_FALSE)
00374                                 {
00375                                         geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL);
00376                                         assert(M->Leaf.PathArray[PathCount]);
00377                                         gePath_Destroy(&(M->Leaf.PathArray[PathCount]));
00378                                         return GE_FALSE;
00379                                 }
00380                         M->Leaf.NameChecksum = geStrBlock_GetChecksum(M->Leaf.NameArray);
00381                 }                                               
00382                                                                                                                         
00383         M->Leaf.PathCount = PathCount+1;
00384         *PathIndex = PathCount;
00385         gePath_CreateRef(P);
00386         return GE_TRUE;
00387 }
00388 
00389 
00390 // returns 0 if there is no name information... or if children don't all share the same checksum.
00391 GENESISAPI int32 GENESISCC geMotion_GetNameChecksum(const geMotion *M)
00392 {
00393         assert( M != NULL );
00394         assert( geMotion_IsValid(M) != GE_FALSE );
00395         switch (M->NodeType)
00396                 {
00397                         case (MOTION_NODE_UNDECIDED):
00398                                 return 0;
00399                         case (MOTION_NODE_BRANCH):
00400                                 {
00401                                         int i;
00402                                         int32 Checksum,FirstChecksum;
00403                                         if (M->Branch.MixerCount<1)
00404                                                 return 0;
00405                                         assert( M->Branch.MixerArray[0].Motion );
00406                                         FirstChecksum = geMotion_GetNameChecksum( M->Branch.MixerArray[0].Motion );
00407                                         
00408                                         for (i=1; i<M->Branch.MixerCount; i++)
00409                                                 {
00410                                                         assert( M->Branch.MixerArray[i].Motion );
00411                                                         Checksum = geMotion_GetNameChecksum( M->Branch.MixerArray[i].Motion );
00412                                                         if (Checksum != FirstChecksum)
00413                                                                 return 0;
00414                                                 }
00415                                         return FirstChecksum;
00416                                 }
00417                         case (MOTION_NODE_LEAF):
00418                                 return M->Leaf.NameChecksum;
00419                         default:
00420                                 assert(0);
00421                 }
00422         return 0;
00423 }       
00424 
00425 GENESISAPI geBoolean GENESISCC geMotion_HasNames(const geMotion *M)
00426 {
00427         assert( M != NULL );
00428         assert( geMotion_IsValid(M) != GE_FALSE );
00429         assert( (M->MaintainNames == GE_TRUE) || (M->MaintainNames == GE_FALSE) );
00430         // if M has names, all children of M have names. 
00431         return M->MaintainNames;
00432 }
00433 
00434 GENESISAPI gePath * GENESISCC geMotion_GetPathNamed(const geMotion *M,const char *Name)
00435 {
00436         int i;
00437 
00438         assert( M != NULL );
00439         assert( geMotion_IsValid(M) != GE_FALSE );
00440         
00441         if (M->NodeType != MOTION_NODE_LEAF)
00442                 {       // not an error condition.
00443                         return NULL;
00444                 }
00445                         
00446         assert( M->Leaf.PathCount >=0 );
00447         
00448         if (Name != NULL)       
00449                 {
00450                         if ( M->MaintainNames == GE_TRUE )
00451                                 {
00452                                         for (i=0; i<M->Leaf.PathCount; i++)
00453                                                 {
00454                                                         if ( strcmp(Name,geStrBlock_GetString(M->Leaf.NameArray,i))==0 )
00455                                                                 {
00456                                                                         return M->Leaf.PathArray[i];
00457                                                                 }
00458                                                 }
00459                                 }
00460                 }
00461         return NULL;
00462 }
00463                         
00464 
00465 #define LINEAR_BLEND(a,b,t)  ( (t)*((b)-(a)) + (a) )    
00466                         // linear blend of a and b  0<t<1 where  t=0 ->a and t=1 ->b
00467 
00468 
00469 
00470 GENESISAPI void GENESISCC geMotion_Sample(const geMotion *M, int PathIndex, gePath_TimeType Time, geXForm3d *Transform)
00471 {
00472         geQuaternion Rotation;
00473         geVec3d          Translation;
00474         assert( M           != NULL);
00475         assert( geMotion_IsValid(M) != GE_FALSE );
00476         assert( Transform   != NULL );
00477 
00478         geMotion_SampleChannels(M,PathIndex,Time,&Rotation,&Translation);
00479         geQuaternion_ToMatrix(&Rotation,Transform);
00480         Transform->Translation = Translation;
00481 }
00482 
00483 
00484 GENESISAPI void GENESISCC geMotion_SampleChannels(const geMotion *M, int PathIndex, gePath_TimeType Time, geQuaternion *Rotation, geVec3d *Translation)
00485 {
00486         assert( M           != NULL);
00487         assert( Rotation    != NULL );
00488         assert( Translation != NULL );
00489         assert( geMotion_IsValid(M) != GE_FALSE );
00490 
00491         switch (M->NodeType)
00492                 {
00493                         case (MOTION_NODE_UNDECIDED):
00494                                 assert(0);
00495                                 break;
00496                         case (MOTION_NODE_BRANCH):
00497                                 {
00498                                         geQuaternion R;
00499                                         geVec3d      T;
00500                                         geMotion_Mixer *Mixer;
00501                                         int i;
00502 
00503                                         if ( M->Branch.MixerCount == 0 )
00504                                                 {
00505                                                         geVec3d_Clear(Translation);
00506                                                         geQuaternion_SetNoRotation(Rotation);
00507                                                         return;
00508                                                 }
00509 
00510                                         assert( M->Branch.MixerCount > 0);
00511                                         Mixer = &(M->Branch.MixerArray[0]);
00512                                         
00513                                         assert(Mixer->Motion != NULL );
00514                                         geMotion_SampleChannels(Mixer->Motion,PathIndex,
00515                                                                                         (Time - Mixer->TimeOffset) * Mixer->TimeScale,
00516                                                                                         Rotation,Translation);
00517                                 
00518                                         for (i=1; i<M->Branch.MixerCount; i++)
00519                                                 {
00520                                                         geFloat BlendAmount;
00521                                                         geFloat MixTime;
00522 
00523                                                         Mixer = &(M->Branch.MixerArray[i]);
00524 
00525                                                         assert( Mixer->Motion != NULL );
00526                                                         assert( Mixer->Blend  != NULL );
00527 
00528                                                         MixTime = (Time - Mixer->TimeOffset) * Mixer->TimeScale;
00529 
00530                                                         geMotion_SampleChannels(Mixer->Motion,PathIndex,MixTime,&R,&T);
00531                                                         {
00532                                                                 geVec3d BlendVector;
00533                                                                 geQuaternion Dummy;
00534                                                                 gePath_SampleChannels(Mixer->Blend,MixTime,&Dummy,&BlendVector);
00535                                                                 BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector);
00536                                                         }
00537                                                         geQuaternion_Slerp(Rotation,&R,BlendAmount,Rotation);
00538                                                         Translation->X = LINEAR_BLEND(Translation->X,T.X,BlendAmount);
00539                                                         Translation->Y = LINEAR_BLEND(Translation->Y,T.Y,BlendAmount);
00540                                                         Translation->Z = LINEAR_BLEND(Translation->Z,T.Z,BlendAmount);
00541                                                 }
00542                                 }
00543                                 break;
00544                         case (MOTION_NODE_LEAF):
00545                                 {
00546                                         gePath *P;
00547                                         assert( ( PathIndex >=0 ) && ( PathIndex < M->Leaf.PathCount ) );
00548                                         P= M->Leaf.PathArray[PathIndex];
00549                                         assert( P != NULL );
00550                                         gePath_SampleChannels(P,Time,Rotation,Translation);
00551                                 }
00552                                 break;
00553                         default:
00554                                 assert(0);
00555                 }
00556 }               
00557 
00558 GENESISAPI geBoolean GENESISCC geMotion_SampleNamed(const geMotion *M, const char *PathName, gePath_TimeType Time, geXForm3d *Transform)
00559 {
00560         geQuaternion Rotation;
00561         geVec3d          Translation;
00562         assert( M           != NULL);
00563         assert( geMotion_IsValid(M) != GE_FALSE );
00564         assert( Transform   != NULL );
00565 
00566         if (geMotion_SampleChannelsNamed(M,PathName,Time,&Rotation,&Translation)==GE_FALSE)
00567                 {
00568                         return GE_FALSE;
00569                 }
00570 
00571         geQuaternion_ToMatrix(&Rotation,Transform);
00572         Transform->Translation = Translation;
00573         return GE_TRUE;
00574 }
00575 
00576 
00577 
00578 GENESISAPI geBoolean GENESISCC geMotion_SampleChannelsNamed(const geMotion *M, const char *PathName, gePath_TimeType Time, geQuaternion *Rotation, geVec3d *Translation)
00579 {
00580         geBoolean AnyChannels=GE_FALSE;
00581         assert( M           != NULL);
00582         assert( Rotation    != NULL );
00583         assert( Translation != NULL );
00584         assert( geMotion_IsValid(M) != GE_FALSE );
00585 
00586         switch (M->NodeType)
00587                 {
00588                         case (MOTION_NODE_UNDECIDED):
00589                                 return GE_FALSE;
00590                                 break;
00591                         case (MOTION_NODE_BRANCH):
00592                                 {
00593                                         int i;
00594                                         geQuaternion R;
00595                                         geVec3d T;
00596                                         geMotion_Mixer *Mixer;
00597 
00598                                         if ( M->Branch.MixerCount == 0 )
00599                                                 {
00600                                                         geVec3d_Clear(Translation);
00601                                                         geQuaternion_SetNoRotation(Rotation);
00602                                                         return GE_TRUE;
00603                                                 }
00604 
00605                                         assert( M->Branch.MixerCount > 0 );
00606 
00607                                         for (i=0; i<M->Branch.MixerCount; i++)
00608                                                 {
00609                                                         geFloat BlendAmount;
00610                                                         geFloat MixTime;
00611 
00612                                                         Mixer = &(M->Branch.MixerArray[i]);
00613 
00614                                                         assert( Mixer->Motion != NULL );
00615                                                         assert( Mixer->Blend  != NULL );
00616 
00617                                                         MixTime = (Time - Mixer->TimeOffset) * Mixer->TimeScale;
00618 
00619                                                         // hmm. is BlendAmount still good if there is no path?
00620                                                         if ( geMotion_SampleChannelsNamed(Mixer->Motion,PathName,MixTime,&R,&T)
00621                                                                  != GE_FALSE )
00622                                                                 {
00623                                                                         if (AnyChannels != GE_FALSE)
00624                                                                                 {
00625                                                                                         {
00626                                                                                                 geVec3d BlendVector;
00627                                                                                                 geQuaternion Dummy;
00628                                                                                                 gePath_SampleChannels(Mixer->Blend,MixTime,&Dummy,&BlendVector);
00629                                                                                                 BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector);
00630                                                                                         }
00631                                                                                         geQuaternion_Slerp(Rotation,&R,BlendAmount,Rotation);
00632                                                                                         Translation->X = LINEAR_BLEND(Translation->X,T.X,BlendAmount);
00633                                                                                         Translation->Y = LINEAR_BLEND(Translation->Y,T.Y,BlendAmount);
00634                                                                                         Translation->Z = LINEAR_BLEND(Translation->Z,T.Z,BlendAmount);
00635                                                                                 }
00636                                                                         else
00637                                                                                 {
00638                                                                                         *Rotation = R;
00639                                                                                         *Translation = T;
00640                                                                                         AnyChannels = GE_TRUE;
00641                                                                                 }
00642                                                                 }
00643                                                 }
00644                                 }
00645                                 break;
00646                         case (MOTION_NODE_LEAF):
00647                                 {
00648                                         gePath *P;
00649                                         P = geMotion_GetPathNamed(M, PathName);
00650                                         if (P == NULL)
00651                                                 {
00652                                                         return GE_FALSE;
00653                                                 }
00654                                         gePath_SampleChannels(P,Time,Rotation,Translation);
00655                                         AnyChannels = GE_TRUE;
00656                                 }
00657                                 break;
00658                         default:
00659                                 assert(0);
00660                 }
00661         return AnyChannels;
00662 }               
00663 
00664 
00665 GENESISAPI gePath * GENESISCC geMotion_GetPath(const geMotion *M,int Index)
00666 {
00667         assert( M != NULL );
00668         assert( geMotion_IsValid(M) != GE_FALSE );
00669         
00670         if (M->NodeType != MOTION_NODE_LEAF)
00671                 {       // not an error condition.
00672                         return NULL;
00673                 }
00674                         
00675         assert( M->Leaf.PathCount >=0 );
00676         assert( Index <= M->Leaf.PathCount );
00677         assert( Index >= 0 );
00678 
00679         return M->Leaf.PathArray[Index];
00680 }
00681 
00682 GENESISAPI const char * GENESISCC geMotion_GetNameOfPath(const geMotion *M, int Index)
00683 {
00684         gePath *P;
00685         assert( M != NULL );
00686 
00687         if (M->NodeType!=MOTION_NODE_LEAF)
00688                 {
00689                         return NULL;
00690                 }
00691         if (geMotion_HasNames(M)==GE_FALSE)
00692                 {
00693                         return NULL;
00694                 }
00695 
00696         P = geMotion_GetPath(M,Index);
00697         if (P==NULL)
00698                 {
00699                         return NULL;
00700                 }
00701         assert( M->Leaf.NameArray!=NULL );
00702 
00703         return geStrBlock_GetString(M->Leaf.NameArray,Index);
00704 
00705 }
00706                         
00707         
00708 
00709 GENESISAPI int GENESISCC geMotion_GetPathCount(const geMotion *M)
00710 {
00711         assert( M != NULL );
00712         assert( geMotion_IsValid(M) != GE_FALSE );
00713 
00714         if (M->NodeType != MOTION_NODE_LEAF)
00715                 {       // not an error condition.
00716                         return 0;
00717                 }
00718         assert( M->Leaf.PathCount >=0 );
00719         return M->Leaf.PathCount;
00720 }
00721 
00722 
00723 GENESISAPI geBoolean GENESISCC geMotion_GetTimeExtents(const geMotion *M,gePath_TimeType *StartTime,gePath_TimeType *EndTime)
00724 {
00725         int i,found;
00726         gePath_TimeType Start,End;
00727         assert( M != NULL );
00728         assert( StartTime != NULL );
00729         assert( EndTime != NULL );
00730         assert( geMotion_IsValid(M) != GE_FALSE );
00731 
00732         found = 0;
00733 
00734         switch (M->NodeType)
00735                 {
00736                         case (MOTION_NODE_UNDECIDED):
00737                                 break;
00738                         case (MOTION_NODE_BRANCH):
00739                                 for (i=0; i<M->Branch.MixerCount; i++)
00740                                         {
00741                                                 if (geMotion_GetTimeExtents(M->Branch.MixerArray[i].Motion,&Start,&End)!=GE_FALSE)
00742                                                         {
00743                                                                 found++;
00744 
00745                                                                 // Assertions in AddSubMotion and SetTimeScale prevent TimeScale from being 0.
00746                                                                 End = M->Branch.MixerArray[i].TimeOffset + ((End - Start) / M->Branch.MixerArray[i].TimeScale);
00747                                                                 Start += M->Branch.MixerArray[i].TimeOffset;
00748 
00749                                                                 // If time scale is negative, then End will be < Start, which violates
00750                                                                 // the entire idea of extents.  So we'll swap them.
00751                                                                 if (End < Start)
00752                                                                 {
00753                                                                         geFloat Temp = Start;
00754                                                                         Start = End;
00755                                                                         End = Temp;
00756                                                                 }
00757                                                                 if (found==1)
00758                                                                         {
00759                                                                                 *StartTime = Start;
00760                                                                                 *EndTime   = End;
00761                                                                         }
00762                                                                 else
00763                                                                         {       //found>1
00764                                                                                 *StartTime = MIN(*StartTime,Start);
00765                                                                                 *EndTime   = MAX(*EndTime,End);
00766                                                                         }
00767                                                         }
00768                                         }                                                                               
00769                                 break;                  
00770                         case (MOTION_NODE_LEAF):
00771                                 found = 0;
00772                                 for (i=0; i<M->Leaf.PathCount; i++)
00773                                         {
00774                                                 if (gePath_GetTimeExtents(M->Leaf.PathArray[i],&Start,&End)!=GE_FALSE)
00775                                                         {
00776                                                                 found++;
00777                                                                 if (found==1)
00778                                                                         {
00779                                                                                 *StartTime = Start;
00780                                                                                 *EndTime   = End;
00781                                                                         }
00782                                                                 else
00783                                                                         {       //found>1
00784                                                                                 *StartTime = MIN(*StartTime,Start);
00785                                                                                 *EndTime   = MAX(*EndTime,End);
00786                                                                         }
00787                                                         }
00788                                         }
00789                                 break;
00790                         default:
00791                                 assert(0);
00792                 }
00793         if (found>0)
00794                 {
00795                         return GE_TRUE;
00796                 }
00797         return GE_FALSE;
00798 }                       
00799 
00800 
00801 GENESISAPI int GENESISCC geMotion_GetSubMotionCount(const geMotion *M)
00802 {
00803         assert( M != NULL );
00804         assert( geMotion_IsValid(M) != GE_FALSE );
00805         if (M->NodeType == MOTION_NODE_BRANCH)
00806                 {
00807                         return M->Branch.MixerCount;
00808                 }
00809         return 0;
00810 }
00811 
00812 
00813 #pragma message ("do we want to copy these before returning them?")
00814 GENESISAPI geMotion * GENESISCC geMotion_GetSubMotion(const geMotion *M,int SubMotionIndex)
00815 {
00816         assert( M != NULL );
00817         assert( geMotion_IsValid(M) != GE_FALSE );
00818         if (M->NodeType != MOTION_NODE_BRANCH )
00819                 {
00820                         return NULL;
00821                 }
00822         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
00823         assert( M->Branch.MixerArray != NULL );
00824 
00825         return M->Branch.MixerArray[SubMotionIndex].Motion;
00826 }
00827 
00828 GENESISAPI geMotion * GENESISCC geMotion_GetSubMotionNamed(const geMotion *M,const char *Name)
00829 {
00830         int i;
00831         assert( M != NULL);     
00832         assert( Name != NULL );
00833         assert( geMotion_IsValid(M) != GE_FALSE );
00834 
00835         if (M->NodeType != MOTION_NODE_BRANCH)
00836                 {
00837                         return NULL;
00838                 }
00839         assert( M->Branch.MixerArray != NULL );
00840         for (i=0; i<M->Branch.MixerCount; i++)
00841                 {
00842                         geMotion *MI = M->Branch.MixerArray[i].Motion;
00843                         assert( MI != NULL );
00844                         if (MI->Name!=NULL)
00845                                 {
00846                                         if (strcmp(MI->Name,Name)==0)
00847                                                 {
00848                                                         return MI;
00849                                                 }
00850                                 }
00851                 }
00852         return NULL;
00853 }
00854 
00855 static geBoolean GENESISCC geMotion_SearchForSubMotion(const geMotion *Parent, const geMotion*Child)
00856 {
00857         int i;
00858         assert( Parent != NULL );
00859         assert( Child  != NULL );
00860         assert( geMotion_IsValid(Parent) != GE_FALSE );
00861         assert( geMotion_IsValid(Child) != GE_FALSE );
00862 
00863         if (Parent == Child)
00864                 return GE_TRUE;
00865 
00866         if (Parent->NodeType != MOTION_NODE_BRANCH)
00867                 return GE_FALSE;
00868 
00869         assert( Parent->Branch.MixerArray != NULL );
00870 
00871         for (i=0; i<Parent->Branch.MixerCount; i++)
00872                 {
00873                         assert( Parent->Branch.MixerArray[i].Motion != NULL );
00874                         if (geMotion_SearchForSubMotion(Parent->Branch.MixerArray[i].Motion,Child)==GE_TRUE)
00875                                 return GE_TRUE;
00876                 }
00877         return GE_FALSE;
00878 }
00879 
00880 GENESISAPI geBoolean GENESISCC geMotion_AddSubMotion(geMotion *ParentMotion, 
00881                                                                 geFloat TimeScale, 
00882                                                                 geFloat TimeOffset,
00883                                                                 geMotion *SubMotion, 
00884                                                                 geFloat StartTime, geFloat StartMagnitude,
00885                                                                 geFloat EndTime,   geFloat EndMagnitude,
00886                                                                 const geXForm3d *Transform,
00887                                                                 int *Index)
00888 
00889 {
00890 
00891         int Count;
00892         geMotion_Mixer *NewMixerArray;
00893         assert( ParentMotion != NULL );
00894         assert( TimeScale        != 0.0f );
00895         assert( SubMotion    != NULL );
00896         assert( Index        != NULL );
00897         //assert( Transform    != NULL );
00898         assert( ( StartMagnitude >= 0.0f) && ( StartMagnitude <=1.0f ));
00899         assert( ( EndMagnitude   >= 0.0f) && ( EndMagnitude   <=1.0f ));
00900         assert( geMotion_IsValid(ParentMotion) != GE_FALSE );
00901         assert( geMotion_IsValid(SubMotion) != GE_FALSE );
00902 
00903         switch (ParentMotion->NodeType)
00904                 {
00905                         case (MOTION_NODE_UNDECIDED):
00906                                 if (geMotion_InitNodeAsBranch(ParentMotion)==GE_FALSE)
00907                                         {
00908                                                 geErrorLog_Add(-1, NULL);
00909                                                 return GE_FALSE;
00910                                         }
00911                                 break;
00912                         case (MOTION_NODE_LEAF):
00913                                 {
00914                                         geErrorLog_Add(-1, NULL);
00915                                         return GE_FALSE;
00916                                 }
00917                         case (MOTION_NODE_BRANCH):
00918                                 break;
00919                         default:
00920                                 assert(0);
00921                 }
00922 
00923         if (ParentMotion->MaintainNames != SubMotion->MaintainNames)
00924                 {
00925                         geErrorLog_Add(-1, NULL);  //?
00926                         return GE_FALSE;
00927                 }
00928                 
00929         if (geMotion_SearchForSubMotion(SubMotion,ParentMotion)!=GE_FALSE)
00930                 {
00931                         geErrorLog_Add(-1, NULL);
00932                         return GE_FALSE;
00933                 }
00934                         
00935         Count = ParentMotion->Branch.MixerCount;
00936         NewMixerArray = geRam_Realloc(ParentMotion->Branch.MixerArray, (1+Count) * sizeof(geMotion_Mixer) );
00937         if ( NewMixerArray == NULL )
00938                 {       
00939                         geErrorLog_Add(-1, NULL);
00940                         return GE_FALSE;
00941                 }
00942                 
00943         ParentMotion->Branch.MixerArray = NewMixerArray;
00944         {
00945                 geMotion_Mixer *Mixer;
00946                 geXForm3d BlendKeyTransform;
00947                 Mixer = &(ParentMotion->Branch.MixerArray[Count]);
00948         
00949                 Mixer->Motion     = SubMotion;
00950                 Mixer->TimeScale  = TimeScale;
00951                 Mixer->TimeOffset = TimeOffset;
00952                 
00953                 Mixer->Blend = gePath_Create(GE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV,GE_PATH_INTERPOLATE_SLERP,GE_FALSE);
00954                 if (Mixer->Blend==NULL)
00955                         {       
00956                                 geErrorLog_Add(-1, NULL);
00957                                 return GE_FALSE;
00958                         }
00959                 MOTION_BLEND_PART_OF_TRANSFORM(BlendKeyTransform) = StartMagnitude;
00960                 if (gePath_InsertKeyframe(Mixer->Blend,
00961                                                 GE_PATH_TRANSLATION_CHANNEL,StartTime,&BlendKeyTransform)==GE_FALSE)
00962                         {
00963                                 geErrorLog_Add(-1, NULL);
00964                                 gePath_Destroy(&(Mixer->Blend));
00965                                 return GE_FALSE;
00966                         }
00967 
00968                 MOTION_BLEND_PART_OF_TRANSFORM(BlendKeyTransform) = EndMagnitude;
00969                 if (gePath_InsertKeyframe(Mixer->Blend,
00970                                                 GE_PATH_TRANSLATION_CHANNEL,EndTime,&BlendKeyTransform)==GE_FALSE)
00971                         {
00972                                 geErrorLog_Add(-1, NULL);
00973                                 gePath_Destroy(&(Mixer->Blend));
00974                                 return GE_FALSE;
00975                         }
00976                 if (Transform == NULL)
00977                         {
00978                                 Mixer->TransformUsed = GE_FALSE;
00979                         }
00980                 else
00981                         {
00982                                 Mixer->TransformUsed = GE_TRUE;
00983                                 Mixer->Transform = *Transform;
00984                         }
00985         }
00986         
00987         *Index = Count;
00988         SubMotion->CloneCount++;
00989         ParentMotion->Branch.MixerCount++;
00990 
00991         return GE_TRUE;
00992 }
00993 
00994 GENESISAPI geMotion * GENESISCC geMotion_RemoveSubMotion(geMotion *ParentMotion, int SubMotionIndex)
00995 {
00996         int Count;
00997         geMotion *M;
00998         assert( ParentMotion != NULL );
00999         assert( geMotion_IsValid(ParentMotion) != GE_FALSE );
01000 
01001         if (ParentMotion->NodeType != MOTION_NODE_BRANCH)
01002                 {
01003                         return NULL;
01004                 }
01005         
01006         Count = ParentMotion->Branch.MixerCount;
01007         assert( (SubMotionIndex>=0) && (SubMotionIndex<Count));
01008         
01009         M = ParentMotion->Branch.MixerArray[SubMotionIndex].Motion;
01010         assert( ParentMotion->Branch.MixerArray[SubMotionIndex].Blend != NULL );
01011         gePath_Destroy( &(ParentMotion->Branch.MixerArray[SubMotionIndex].Blend) );
01012         
01013         if (Count>1)
01014                 {
01015                         memcpy( &(ParentMotion->Branch.MixerArray[SubMotionIndex]),
01016                                         &(ParentMotion->Branch.MixerArray[SubMotionIndex+1]),
01017                                         sizeof(geMotion_Mixer) * (Count-(SubMotionIndex+1)));
01018                 }
01019         ParentMotion->Branch.MixerCount--;
01020 
01021         {
01022                 geMotion_Mixer *NewMixerArray;
01023                 if (ParentMotion->Branch.MixerCount == 0)
01024                         {
01025                                 geRam_Free(ParentMotion->Branch.MixerArray);
01026                                 ParentMotion->Branch.MixerArray = NULL;
01027                         }
01028                 else
01029                         {
01030                                 NewMixerArray = geRam_Realloc(ParentMotion->Branch.MixerArray, 
01031                                                                         (ParentMotion->Branch.MixerCount) * sizeof(geMotion_Mixer) );
01032                                 if ( NewMixerArray != NULL )
01033                                         {       
01034                                                 ParentMotion->Branch.MixerArray = NewMixerArray;
01035                                         }
01036                         }
01037         }
01038         geMotion_Destroy( &M );
01039         return M;
01040 }
01041         
01042 
01043 
01044 GENESISAPI geFloat   GENESISCC geMotion_GetTimeOffset( const geMotion *M,int SubMotionIndex )
01045 {
01046         assert( M != NULL );
01047         assert( geMotion_IsValid(M) != GE_FALSE );
01048         // wrong node type is neither error nor invalid.  return value is just 0
01049 
01050         if (M->NodeType == MOTION_NODE_BRANCH)
01051                 {
01052                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01053                         return M->Branch.MixerArray[SubMotionIndex].TimeOffset;
01054                 }
01055         return 0.0f;
01056 }
01057 
01058 GENESISAPI geBoolean  GENESISCC geMotion_SetTimeOffset( geMotion *M,int SubMotionIndex,geFloat TimeOffset )
01059 {
01060         assert( M != NULL );
01061         assert( geMotion_IsValid(M) != GE_FALSE );
01062 
01063         if (M->NodeType == MOTION_NODE_BRANCH)
01064                 {
01065                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01066                         M->Branch.MixerArray[SubMotionIndex].TimeOffset = TimeOffset;
01067                         return GE_TRUE;
01068                 }
01069         return GE_FALSE;
01070 }
01071 
01072 GENESISAPI geFloat   GENESISCC geMotion_GetTimeScale( const geMotion *M,int SubMotionIndex )
01073 {
01074         assert( M != NULL );
01075         assert( geMotion_IsValid(M) != GE_FALSE );
01076         // wrong node type is neither error nor invalid.  return value is just 1
01077 
01078         if (M->NodeType == MOTION_NODE_BRANCH)
01079                 {
01080                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01081                         return M->Branch.MixerArray[SubMotionIndex].TimeScale;
01082                 }
01083         return 1.0f;
01084 }
01085 
01086 GENESISAPI geBoolean  GENESISCC geMotion_SetTimeScale( geMotion *M,int SubMotionIndex,geFloat TimeScale )
01087 {
01088         assert( M != NULL );
01089         assert( geMotion_IsValid(M) != GE_FALSE );
01090         assert( TimeScale != 0.0f);
01091 
01092         if (M->NodeType == MOTION_NODE_BRANCH)
01093                 {
01094                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01095                         M->Branch.MixerArray[SubMotionIndex].TimeScale = TimeScale;
01096                         return GE_TRUE;
01097                 }
01098         return GE_FALSE;
01099 }
01100 
01101 GENESISAPI geFloat    GENESISCC geMotion_GetBlendAmount( const geMotion *M, int SubMotionIndex, geFloat Time)
01102 {
01103         assert( M != NULL );
01104         assert( geMotion_IsValid(M) != GE_FALSE );
01105         // wrong node type is neither error nor invalid.  return value is just 0
01106 
01107         if (M->NodeType == MOTION_NODE_BRANCH)
01108                 {
01109                         geQuaternion Dummy;
01110                         geVec3d BlendVector;
01111                         geFloat BlendAmount;
01112 
01113                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01114                         assert( M->Branch.MixerArray[SubMotionIndex].Blend != NULL );
01115                         gePath_SampleChannels(M->Branch.MixerArray[SubMotionIndex].Blend,
01116                                                                   ( Time - M->Branch.MixerArray[SubMotionIndex].TimeOffset )
01117                                                                     * M->Branch.MixerArray[SubMotionIndex].TimeScale,
01118                                                                    &Dummy,&BlendVector);
01119                         BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector);
01120                         return BlendAmount;
01121                 }
01122         return 0.0f;
01123 }
01124 
01125 GENESISAPI gePath    * GENESISCC geMotion_GetBlendPath( const geMotion *M,int SubMotionIndex )
01126 {
01127         assert( M != NULL );
01128         assert( geMotion_IsValid(M) != GE_FALSE );
01129         // wrong node type is neither error nor invalid.  return value is just NULL
01130 
01131         if (M->NodeType == MOTION_NODE_BRANCH)
01132                 {
01133                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01134                         return M->Branch.MixerArray[SubMotionIndex].Blend;
01135                 }
01136         return NULL;
01137 }
01138 
01139 GENESISAPI geBoolean  GENESISCC geMotion_SetBlendPath( geMotion *M,int SubMotionIndex, gePath *Blend )
01140 {
01141         assert( M != NULL );
01142         assert( geMotion_IsValid(M) != GE_FALSE );
01143         if (M->NodeType == MOTION_NODE_BRANCH)
01144                 {
01145                         gePath *P;
01146                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01147                         assert( Blend != NULL );
01148                         P = M->Branch.MixerArray[SubMotionIndex].Blend;
01149                         gePath_Destroy(&P);
01150                         P = gePath_CreateCopy(Blend);
01151                         if ( P == NULL )
01152                                 {
01153                                         geErrorLog_Add(-1, NULL);
01154                                         return GE_FALSE;
01155                                 }
01156                         M->Branch.MixerArray[SubMotionIndex].Blend = P;
01157                         return GE_TRUE;
01158                 }
01159         return GE_FALSE;
01160 }
01161 
01162 
01163 GENESISAPI const geXForm3d * GENESISCC geMotion_GetBaseTransform( const geMotion *M,int SubMotionIndex )
01164 {
01165         assert( M != NULL );
01166         assert( geMotion_IsValid(M) != GE_FALSE );
01167         // wrong node type is neither error nor invalid.  return value is just NULL
01168 
01169         if (M->NodeType == MOTION_NODE_BRANCH)
01170                 {
01171                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01172                         if (M->Branch.MixerArray[SubMotionIndex].TransformUsed != GE_FALSE)
01173                                 {
01174                                         return &(M->Branch.MixerArray[SubMotionIndex].Transform);
01175                                 }
01176                         else
01177                                 {
01178                                         return NULL;
01179                                 }
01180                 }
01181         return NULL;
01182 }
01183 
01184 GENESISAPI geBoolean  GENESISCC geMotion_SetBaseTransform( geMotion *M,int SubMotionIndex, geXForm3d *BaseTransform )
01185 {
01186         assert( M != NULL );
01187         assert( geMotion_IsValid(M) != GE_FALSE );
01188 
01189         if (M->NodeType == MOTION_NODE_BRANCH)
01190                 {
01191                         assert( (SubMotionIndex>=0) && (SubMotionIndex<M->Branch.MixerCount));
01192                         assert( BaseTransform != NULL );
01193                         if (BaseTransform!=NULL)
01194                                 {
01195                                         M->Branch.MixerArray[SubMotionIndex].Transform     = *BaseTransform;
01196                                         M->Branch.MixerArray[SubMotionIndex].TransformUsed = GE_TRUE;
01197                                 }
01198                         else
01199                                 {
01200                                         M->Branch.MixerArray[SubMotionIndex].TransformUsed = GE_FALSE;
01201                                 }
01202                                         
01203                         return GE_TRUE;
01204                 }
01205         return GE_FALSE;
01206 }
01207 
01208 
01209 #pragma warning( disable : 4701)        // don't want to set Translation until we are ready
01210 GENESISAPI geBoolean GENESISCC geMotion_GetTransform( const geMotion *M, geFloat Time, geXForm3d *Transform)
01211 {
01212         assert( M         != NULL);
01213         assert( geMotion_IsValid(M) != GE_FALSE );
01214 
01215         switch (M->NodeType)
01216                 {
01217                         case (MOTION_NODE_UNDECIDED):
01218                                 {
01219                                         return GE_FALSE;
01220                                 }
01221                                 break;
01222                         case (MOTION_NODE_BRANCH):
01223                                 {
01224                                         geQuaternion R,Rotation;
01225                                         geVec3d      T,Translation;
01226                                         geMotion_Mixer *Mixer;
01227                                         geFloat MixTime;
01228                                         int i;
01229                                         int MixCount=0;
01230 
01231                                         if ( M->Branch.MixerCount == 0 )
01232                                                 {
01233                                                         return GE_FALSE;
01234                                                 }
01235                                         assert( M->Branch.MixerCount > 0 );
01236 
01237                                         for (i=0; i<M->Branch.MixerCount; i++)
01238                                                 {
01239                                                         geFloat BlendAmount;
01240                                                         geBoolean DoMix=GE_FALSE;
01241 
01242                                                         Mixer = &(M->Branch.MixerArray[i]);
01243 
01244                                                         assert( Mixer->Motion != NULL );
01245                                                         assert( Mixer->Blend  != NULL );
01246                                                         
01247                                                         MixTime = (Time - Mixer->TimeOffset) * Mixer->TimeScale;
01248                                                         if (geMotion_GetTransform(Mixer->Motion,MixTime,Transform)!=GE_FALSE)
01249                                                                 {
01250                                                                         DoMix=GE_TRUE;
01251                                                                         if (Mixer->TransformUsed!=GE_FALSE)
01252                                                                                 {
01253                                                                                         geXForm3d_Multiply(&(Mixer->Transform),Transform,Transform);
01254                                                                                 }
01255                                                                 }
01256                                                         else
01257                                                                 {
01258                                                                         if (Mixer->TransformUsed!=GE_FALSE)
01259                                                                                 {
01260                                                                                         DoMix = GE_TRUE;
01261                                                                                         *Transform = Mixer->Transform;
01262                                                                                 }
01263                                                                 }
01264                                                         if (DoMix!=GE_FALSE)
01265                                                                 {
01266                                                                         if (MixCount==0)
01267                                                                                 {
01268                                                                                         geQuaternion_FromMatrix(Transform,&Rotation);
01269                                                                                         Translation = Transform->Translation;
01270                                                                                 }
01271                                                                         else
01272                                                                                 {
01273                                                                                         geQuaternion_FromMatrix(Transform,&R);
01274                                                                                         T = Transform->Translation;
01275                                                                                         {
01276                                                                                                 geVec3d BlendVector;
01277                                                                                                 geQuaternion Dummy;
01278                                                                                                 gePath_SampleChannels(Mixer->Blend,MixTime,&Dummy,&BlendVector);
01279                                                                                                 BlendAmount = MOTION_BLEND_PART_OF_VECTOR(BlendVector);
01280                                                                                         }
01281                                                                                         geQuaternion_Slerp(&Rotation,&R,BlendAmount,&Rotation);
01282                                                                                         Translation.X = LINEAR_BLEND(Translation.X,T.X,BlendAmount);
01283                                                                                         Translation.Y = LINEAR_BLEND(Translation.Y,T.Y,BlendAmount);
01284                                                                                         Translation.Z = LINEAR_BLEND(Translation.Z,T.Z,BlendAmount);
01285                                                                                 }
01286                                                                         
01287                                                                         MixCount++;
01288                                                                 }
01289                                                 }
01290                                         if (MixCount>0)
01291                                                 {
01292                                                         geQuaternion_ToMatrix(&Rotation,Transform);
01293                                                         Transform->Translation = Translation;
01294                                                         return GE_TRUE;
01295                                                 }
01296                                         return GE_FALSE;
01297                                 }
01298                                 break;
01299                         case (MOTION_NODE_LEAF):
01300                                 {
01301                                         return GE_FALSE;
01302                                 }
01303                                 break;
01304                         default:
01305                                 assert(0);
01306                 }
01307         return GE_FALSE;
01308 }
01309 #pragma warning( default : 4701)        
01310 
01311 
01312 //--------------------------------------------------------------------------------------------
01313 //   Event Support
01314 
01315 GENESISAPI geBoolean GENESISCC geMotion_GetEventExtents(const geMotion *M,geFloat *FirstEventTime,geFloat *LastEventTime)
01316 {
01317         assert( M != NULL );
01318         assert( geMotion_IsValid(M) != GE_FALSE );
01319         assert( FirstEventTime != NULL );
01320         assert( LastEventTime != NULL );
01321 
01322         return geTKEvents_GetExtents(M->Leaf.Events,FirstEventTime,LastEventTime);
01323 }       
01324 
01325 
01326         // Inserts the new event and corresponding string.
01327 GENESISAPI geBoolean GENESISCC geMotion_InsertEvent(geMotion *M, gePath_TimeType tKey, const char* String)
01328 {
01329         assert( M != NULL );
01330         assert( geMotion_IsValid(M) != GE_FALSE );
01331         assert( String != NULL );
01332 
01333         if (M->NodeType != MOTION_NODE_LEAF )
01334                 {
01335                         geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL);
01336                         return GE_FALSE;
01337                 }
01338 
01339         if (M->Leaf.Events == NULL)
01340                 {
01341                         M->Leaf.Events = geTKEvents_Create();
01342                         if ( M->Leaf.Events == NULL )
01343                                 {
01344                                         geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL);
01345                                         return GE_FALSE;
01346                                 }
01347                 }
01348         if (geTKEvents_Insert(M->Leaf.Events, tKey,String)==GE_FALSE)
01349                 {
01350                         geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL);
01351                         return GE_FALSE;
01352                 };
01353         return GE_TRUE;
01354 }
01355         
01356 
01357                         
01358         // Deletes the event
01359 GENESISAPI geBoolean GENESISCC geMotion_DeleteEvent(geMotion *M, gePath_TimeType tKey)
01360 {
01361         assert( M != NULL);
01362         assert( geMotion_IsValid(M) != GE_FALSE );
01363 
01364         if (M->NodeType != MOTION_NODE_LEAF )
01365                 {
01366                         geErrorLog_Add(ERR_MOTION_INSERT_EVENT, NULL);
01367                         return GE_FALSE;
01368                 }
01369         if ( M->Leaf.Events == NULL )
01370                 {
01371                         geErrorLog_Add(ERR_MOTION_DELETE_EVENT, NULL);
01372                         return GE_FALSE;
01373                 }
01374         if (geTKEvents_Delete(M->Leaf.Events,tKey)==GE_FALSE)
01375                 {
01376                         geErrorLog_Add(ERR_MOTION_DELETE_EVENT, NULL);
01377                         return GE_FALSE;
01378                 }
01379         return GE_TRUE;
01380 }
01381 
01382 GENESISAPI void GENESISCC geMotion_SetupEventIterator(
01383         geMotion *M,
01384         gePath_TimeType StartTime,                              // Inclusive search start
01385         gePath_TimeType EndTime)                                // Non-inclusive search stop
01386         // For searching or querying the array for events between two times
01387         // times are compaired [StartTime,EndTime), '[' is inclusive, ')' is 
01388         // non-inclusive.  This prepares the geMotion_GetNextEvent() function.
01389 {
01390         int i;
01391         assert( M != NULL);
01392         assert( geMotion_IsValid(M) != GE_FALSE );
01393 
01394         switch (M->NodeType)
01395                 {
01396                         case (MOTION_NODE_UNDECIDED):
01397                                 break;
01398                         case (MOTION_NODE_LEAF):
01399                                 if ( M->Leaf.Events != NULL )
01400                                         {
01401                                                 geTKEvents_SetupIterator(M->Leaf.Events,StartTime,EndTime);
01402                                         }       
01403                                 break;
01404                         case (MOTION_NODE_BRANCH):
01405                                 for (i=0; i<M->Branch.MixerCount; i++)
01406                                         {
01407                                                 geMotion_Mixer *Mixer;
01408                                 
01409                                                 Mixer = &(M->Branch.MixerArray[i]);
01410 
01411                                                 geMotion_SetupEventIterator(Mixer->Motion,
01412                                                         (StartTime - Mixer->TimeOffset) * Mixer->TimeScale,
01413                                                         (EndTime - Mixer->TimeOffset) * Mixer->TimeScale);
01414                                         }
01415                                 M->Branch.CurrentEventIterator =0;
01416                                 break;
01417                         default:
01418                                 assert(0);
01419                 }
01420 }               
01421 
01422 
01423 GENESISAPI geBoolean GENESISCC geMotion_GetNextEvent(
01424         geMotion *M,                                            // Event list to iterate
01425         gePath_TimeType *pTime,                         // Return time, if found
01426         const char **ppEventString)             // Return data, if found
01427         // Iterates from StartTime to EndTime as setup in geMotion_SetupEventIterator()
01428         // and for each event between these times [StartTime,EndTime)
01429         // this function will return Time and EventString returned for that event
01430         // and the iterator will be positioned for the next search.  When there 
01431         // are no more events in the range, this function will return GE_FALSE (Time
01432         // will be 0 and ppEventString will be empty).
01433 {
01434         assert( M != NULL);
01435         assert( geMotion_IsValid(M) != GE_FALSE );
01436 
01437         assert( pTime != NULL );
01438         assert( ppEventString != NULL );
01439 
01440         switch (M->NodeType)
01441                 {
01442                         case (MOTION_NODE_UNDECIDED):
01443                                 {
01444                                         return GE_FALSE;
01445                                 }
01446                                 break;
01447                         case (MOTION_NODE_LEAF):
01448                                 if ( M->Leaf.Events != NULL )
01449                                         {
01450                                                 return geTKEvents_GetNextEvent(M->Leaf.Events,pTime,ppEventString);
01451                                         }       
01452                                 break;
01453                         case (MOTION_NODE_BRANCH):
01454                                 while (M->Branch.CurrentEventIterator < M->Branch.MixerCount)
01455                                         {
01456                                                 if (geMotion_GetNextEvent(
01457                                                                         M->Branch.MixerArray[M->Branch.CurrentEventIterator].Motion,
01458                                                                         pTime,ppEventString) !=GE_FALSE)
01459                                                         return GE_TRUE;
01460                                                 M->Branch.CurrentEventIterator++;
01461                                         }
01462                                 break;
01463                         default:
01464                                 assert(0);
01465                 }
01466 
01467         return GE_FALSE;
01468 }
01469         
01470 //------------------------------------------------------------------------------------------------------
01471 //    Read/Write support
01472 
01473 
01474 #define CHECK_FOR_WRITE(uu) if(uu <= 0) { geErrorLog_Add( ERR_MOTION_FILE_WRITE, NULL ); return GE_FALSE; }
01475 
01476 #define MOTION_ASCII_FILE_TYPE 0x4E544F4D       // 'MOTN'
01477 #define MOTION_BIN_FILE_TYPE 0x424E544D         // 'MTNB'
01478 #define MOTION_FILE_VERSION 0x00F0                      // Restrict version to 16 bits
01479 
01480 
01481 #define MOTION_NAME_ID                  "NameID"
01482 #define MOTION_MAINTAINNAMES_ID "MaintainNames"
01483 
01484 #define MOTION_NUM_ASCII_IDS     6      // Keep this up to date
01485 
01486 #define MOTION_PATHCOUNT_ID     "PathCount"
01487 #define MOTION_NAMECHECKSUM_ID  "NameChecksum"
01488 #define MOTION_EVENTS_ID                "Events"
01489 #define MOTION_NAMEARRAY_ID             "NameArray"
01490 #define MOTION_PATHARRAY_ID             "PathArray"
01491 #define LEAF_NUM_ASCII_IDS              5  // keep this up to date
01492 
01493 #define MOTION_MixerCount_ID   "MixerCount"
01494 #define MOTION_MOTION_ARRAY             "MotionArray"
01495 #define MOTION_BLEND_ARRAY              "BlendArray"
01496 #define BRANCH_NUM_ASCII_IDS    3  // keep this up to date
01497 
01498 static geMotion *GENESISCC geMotion_CreateFromBinaryFile(geVFile *pFile);
01499 
01500 
01501 GENESISAPI geMotion* GENESISCC geMotion_CreateFromFile(geVFile* pFile)
01502 {
01503         uint32 u, v;
01504         geMotion* M;
01505 
01506         assert( pFile != NULL );
01507 
01508         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
01509         {
01510                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01511                 return NULL;
01512         }
01513 
01514         if(u == MOTION_ASCII_FILE_TYPE)
01515         {
01516                 int NumItemsNeeded=0;
01517                 int NumItemsRead = 0;
01518                 #define LINE_LENGTH 256
01519                 char line[LINE_LENGTH];
01520 
01521                 M = geMotion_Create(GE_FALSE);
01522                 if( M == NULL )
01523                 {
01524                         geErrorLog_Add(-1, NULL);
01525                         return NULL;            // error logged already in geMotion_Create
01526                 }
01527         
01528                 // Read and build the version.  Then determine the number of items to read.
01529                 if      (geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01530                         {
01531                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01532                                 return NULL;
01533                         }
01534                 if      (sscanf(line, "%X.%X\n", &u, &v) != 2)
01535                         {
01536                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01537                                 return NULL;
01538                         }
01539                 v |= (u << 8);
01540                 if(v >= MOTION_FILE_VERSION)
01541                 {
01542                         NumItemsNeeded = MOTION_NUM_ASCII_IDS;
01543                 }
01544 
01545                 // remove this when leaf/branch split happens.
01546                 if (geMotion_InitNodeAsLeaf(M,GE_FALSE)==GE_FALSE)
01547                 {
01548                         geErrorLog_Add(-1, NULL);
01549                         return GE_FALSE;
01550                 }
01551 
01552 
01553                 while(NumItemsRead < NumItemsNeeded)
01554                 {
01555                         if(geVFile_GetS(pFile, line, LINE_LENGTH) == GE_FALSE)
01556                                 {
01557                                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01558                                         break; // got to read something
01559                                 }
01560                         else if(strnicmp(line, MOTION_NAME_ID, sizeof(MOTION_NAME_ID)-1) == 0)
01561                         {
01562                                 //line[strlen(line)-1]=0;  // zap off cr
01563                                 if ( line[0] != 0 )
01564                                         line[strlen(line)-1] = 0;       // remove trailing /n  (textmode)
01565                                 if ( line[0] != 0 )
01566                                         {
01567                                                 int len = strlen(line)-1;
01568                                                 if (line[len] == 13)  // remove trailing /r  (binary file mode)
01569                                                         {
01570                                                                 line[len] = 0;
01571                                                         }
01572                                         }
01573                                 if (strlen(line) > sizeof(MOTION_NAME_ID))
01574                                         {
01575                                                 if (geMotion_SetName(M,line+sizeof(MOTION_NAME_ID))==GE_FALSE)
01576                                                         {                                               
01577                                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01578                                                                 break;           
01579                                                         }
01580                                         }
01581                                 //NumItemsRead++;
01582                         }
01583                         
01584                         else if(strnicmp(line, MOTION_MAINTAINNAMES_ID, sizeof(MOTION_MAINTAINNAMES_ID)-1) == 0)
01585                         {
01586                                 if(sscanf(line + sizeof(MOTION_MAINTAINNAMES_ID)-1, "%d", &M->MaintainNames) != 1)
01587                                         {                                               
01588                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01589                                                 break;
01590                                         }
01591                                 NumItemsRead++;
01592                         }
01593                         else if(strnicmp(line, MOTION_PATHCOUNT_ID, sizeof(MOTION_PATHCOUNT_ID)-1) == 0)
01594                         {
01595                                 if(sscanf(line + sizeof(MOTION_PATHCOUNT_ID)-1, "%d", &M->Leaf.PathCount) != 1)
01596                                         {                                               
01597                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01598                                                 break;           
01599                                         }
01600                                 NumItemsRead++;
01601                         }
01602                         else if(strnicmp(line, MOTION_NAMECHECKSUM_ID, sizeof(MOTION_NAMECHECKSUM_ID)-1) == 0)
01603                         {
01604                                 if(sscanf(line + sizeof(MOTION_NAMECHECKSUM_ID)-1, "%d", &M->Leaf.NameChecksum) != 1)
01605                                         {                                               
01606                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01607                                                 break;
01608                                         }
01609                                 NumItemsRead++;
01610                         }
01611                         else if(strnicmp(line, MOTION_EVENTS_ID, sizeof(MOTION_EVENTS_ID)-1) == 0)
01612                         {
01613                                 int flag;
01614                                 if(sscanf(line + sizeof(MOTION_EVENTS_ID)-1, "%d", &flag) != 1)
01615                                         {                                               
01616                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01617                                                 break;
01618                                         }
01619                                 if (flag!=GE_FALSE)
01620                                         {
01621                                                 M->Leaf.Events = geTKEvents_CreateFromFile(pFile);
01622                                                 if (M->Leaf.Events == NULL)
01623                                                         {                                               
01624                                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01625                                                                 break;
01626                                                         }
01627                                         }
01628                                 NumItemsRead++;
01629                         }
01630                         else if(strnicmp(line, MOTION_NAMEARRAY_ID, sizeof(MOTION_NAMEARRAY_ID)-1) == 0)
01631                         {
01632                                 int flag;
01633                                 if(sscanf(line + sizeof(MOTION_NAMEARRAY_ID)-1, "%d", &flag) != 1)
01634                                         {                                               
01635                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01636                                                 break;
01637                                         }
01638                                 if (flag!=GE_FALSE)
01639                                         {
01640                                                 M->Leaf.NameArray = geStrBlock_CreateFromFile(pFile);
01641                                                 if (M->Leaf.NameArray == NULL)
01642                                                         {                                               
01643                                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01644                                                                 break;
01645                                                         }
01646                                         }
01647                                 NumItemsRead++;
01648                         }
01649                         else if(strnicmp(line, MOTION_PATHARRAY_ID, sizeof(MOTION_PATHARRAY_ID)-1) == 0)
01650                         {
01651                                 int i,count;
01652                                 if(sscanf(line + sizeof(MOTION_PATHARRAY_ID)-1, "%d", &count) != 1)
01653                                         {                                               
01654                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01655                                                 break;
01656                                         }
01657 
01658                                 M->Leaf.PathArray = geRam_Allocate( count * sizeof(gePath*) );
01659 
01660                                 if ( M->Leaf.PathArray == NULL )
01661                                         {       
01662                                                 geErrorLog_Add(ERR_MOTION_ADDPATH_ENOMEM, NULL);
01663                                                 break;
01664                                         }
01665 
01666                                 for (i=0; i<count; i++)
01667                                         {
01668                                                         
01669                                                 M->Leaf.PathArray[i] = gePath_CreateFromFile(pFile);
01670                                                 if (M->Leaf.PathArray[i] == NULL )
01671                                                         {
01672                                                                 geErrorLog_Add(ERR_MOTION_FILE_READ, NULL);
01673                                                                 break;
01674                                                         }
01675         
01676                                         }
01677                                 NumItemsRead++;
01678                         }
01679 
01680 
01681                 }
01682                 
01683                 if(NumItemsNeeded == NumItemsRead)
01684                         {
01685                                 return M;
01686                         }
01687                 else
01688                         {
01689                                 geErrorLog_Add( ERR_MOTION_FILE_PARSE , NULL);
01690                                 geMotion_Destroy(&M); // try to destroy it
01691                                 return NULL;
01692                         }
01693         }
01694         else
01695                 {
01696                         if (u==MOTION_BIN_FILE_TYPE)
01697                                 {
01698                                         return geMotion_CreateFromBinaryFile(pFile);
01699                                 }
01700                 }
01701 
01702         geErrorLog_Add( ERR_MOTION_FILE_PARSE , NULL);
01703         return NULL;
01704 }
01705 
01706 static geBoolean GENESISCC geMotion_WriteLeaf(const geMotion *M, geVFile *pFile)
01707 {
01708         int i;
01709         int flag;
01710 
01711         assert( M != NULL );
01712         assert( pFile != NULL );
01713         assert( M->NodeType == MOTION_NODE_LEAF);
01714         assert( geMotion_IsValid(M) != GE_FALSE );
01715 
01716         if (M->Leaf.Events == NULL)
01717                 flag = GE_FALSE;
01718         else
01719                 flag = GE_TRUE;
01720 
01721         if      (geVFile_Printf(pFile, "%s %d\n", MOTION_PATHCOUNT_ID,M->Leaf.PathCount) == GE_FALSE)
01722                 {
01723                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01724                         return GE_FALSE; 
01725                 }
01726         if      (geVFile_Printf(pFile, "%s %d\n", MOTION_NAMECHECKSUM_ID,M->Leaf.NameChecksum) == GE_FALSE)
01727                 {
01728                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01729                         return GE_FALSE; 
01730                 }
01731 
01732         if      (geVFile_Printf(pFile, "%s %d\n", MOTION_EVENTS_ID, flag) == GE_FALSE)
01733                 {
01734                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01735                         return GE_FALSE; 
01736                 }
01737 
01738         if (flag != GE_FALSE)
01739                 {
01740                         if (geTKEvents_WriteToFile(M->Leaf.Events,pFile)==GE_FALSE)
01741                                 {
01742                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01743                                         return GE_FALSE; 
01744                                 }
01745                 }
01746 
01747         if (M->Leaf.NameArray == NULL)
01748                 flag = GE_FALSE;
01749         else
01750                 flag = GE_TRUE;
01751         if      (geVFile_Printf(pFile, "%s %d\n", MOTION_NAMEARRAY_ID, flag) == GE_FALSE)
01752                 {
01753                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01754                         return GE_FALSE; 
01755                 }
01756         if (flag != GE_FALSE)
01757                 {
01758                         if (geStrBlock_WriteToFile(M->Leaf.NameArray,pFile)==GE_FALSE)
01759                                 {
01760                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01761                                         return GE_FALSE; 
01762                                 }
01763                 }
01764 
01765         if      (geVFile_Printf(pFile, "%s %d\n", MOTION_PATHARRAY_ID, M->Leaf.PathCount) == GE_FALSE)
01766                 {
01767                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01768                         return GE_FALSE; 
01769                 }
01770         for (i=0; i<M->Leaf.PathCount; i++)
01771                 {
01772                         if (gePath_WriteToFile(M->Leaf.PathArray[i],pFile) == GE_FALSE)
01773                                 {
01774                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
01775                                         return GE_FALSE; 
01776                                 }
01777                 }
01778         return GE_TRUE;
01779 }
01780 
01781 static geBoolean GENESISCC geMotion_WriteBranch(const geMotion *M, geVFile *pFile)
01782 {
01783         assert( M != NULL );
01784         assert( pFile != NULL );
01785         assert( M->NodeType == MOTION_NODE_BRANCH);
01786         assert( geMotion_IsValid(M) != GE_FALSE );
01787         #pragma message("finish this")
01788         return GE_FALSE;
01789 }
01790 
01791 
01792 GENESISAPI geBoolean GENESISCC geMotion_WriteToFile(const geMotion *M, geVFile *pFile)
01793 {
01794         uint32 u;
01795 
01796         assert( M != NULL );
01797         assert( pFile != NULL );
01798         assert( geMotion_IsValid(M) != GE_FALSE );
01799 
01800 
01801         // Write the format flag
01802         u = MOTION_ASCII_FILE_TYPE;
01803         if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE)
01804         {
01805                 geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
01806                 return GE_FALSE;
01807         }
01808 
01809 
01810         // Write the version
01811         if      (geVFile_Printf(pFile, " %X.%.2X\n", (MOTION_FILE_VERSION & 0xFF00) >> 8, 
01812                                                                         MOTION_FILE_VERSION & 0x00FF) == GE_FALSE)
01813                 {
01814                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
01815                         return GE_FALSE;
01816                 }
01817 
01818         if      (geVFile_Printf(pFile, "%s %s\n", MOTION_NAME_ID,(M->Name==NULL)?(""):(M->Name)) == GE_FALSE)
01819                 {
01820                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
01821                         return GE_FALSE;
01822                 }
01823 
01824         if      (geVFile_Printf(pFile, "%s %d\n", MOTION_MAINTAINNAMES_ID,M->MaintainNames) == GE_FALSE)
01825                 {
01826                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
01827                         return GE_FALSE;
01828                 }
01829 
01830         switch (M->NodeType)
01831                 {
01832                         case (MOTION_NODE_UNDECIDED):
01833                                 break;
01834                         case (MOTION_NODE_BRANCH):
01835                                 if (geMotion_WriteBranch(M,pFile)==GE_FALSE)
01836                                         {
01837                                                 geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
01838                                                 return GE_FALSE;
01839                                         }
01840                                 break;
01841                         case (MOTION_NODE_LEAF):
01842                                 if (geMotion_WriteLeaf(M,pFile)==GE_FALSE)
01843                                         {
01844                                                 geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
01845                                                 return GE_FALSE;
01846                                         }
01847                                 break;
01848                         default:
01849                                 assert(0);
01850                                 break;
01851                 }
01852         return GE_TRUE;
01853 }
01854 
01855 
01856 
01857 typedef struct
01858 {
01859         int PathCount;
01860         int32 NameChecksum;
01861         uint32 Flags;
01862 } geMotion_BinaryFileLeafHeader;
01863 
01864 static geBoolean GENESISCC geMotion_ReadBinaryBranch(geMotion *M, geVFile *pFile)
01865 {
01866         assert( M != NULL );
01867         assert( pFile != NULL );
01868         if (geMotion_InitNodeAsBranch(M)==GE_FALSE)
01869                 {
01870                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01871                         return GE_FALSE;
01872                 }
01873 
01874         #pragma message("finish this")
01875         return GE_FALSE;
01876 }
01877 
01878 static geBoolean GENESISCC geMotion_ReadBinaryLeaf(geMotion *M, geVFile *pFile)
01879 {
01880         int i;
01881         geMotion_BinaryFileLeafHeader Header;
01882         assert( M != NULL );
01883         assert( pFile != NULL );
01884         if (geMotion_InitNodeAsLeaf(M,GE_FALSE)==GE_FALSE)
01885                 {
01886                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01887                         return GE_FALSE;
01888                 }
01889 
01890         if (geVFile_Read(pFile, &Header, sizeof(geMotion_BinaryFileLeafHeader)) == GE_FALSE)
01891                 {
01892                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); 
01893                         return GE_FALSE; 
01894                 }
01895         M->Leaf.NameChecksum = Header.NameChecksum;
01896         
01897         if (Header.Flags & 0x1)
01898                 {
01899                         M->Leaf.Events = geTKEvents_CreateFromFile(pFile);
01900                         if (M->Leaf.Events == NULL )
01901                                 {
01902                                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); 
01903                                         return GE_FALSE; 
01904                                 }
01905                 }
01906         else
01907                 {
01908                         M->Leaf.Events = NULL;
01909                 }
01910 
01911         if (Header.Flags & 0x2)
01912                 {
01913                         M->Leaf.NameArray = geStrBlock_CreateFromFile(pFile);
01914                         if (M->Leaf.NameArray == NULL)
01915                                 {
01916                                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); 
01917                                         return GE_FALSE; 
01918                                 }
01919                 }
01920         else
01921                 {
01922                         M->Leaf.NameArray = NULL;
01923                 }
01924 
01925         M->Leaf.PathCount = 0;
01926         M->Leaf.PathArray = geRam_Allocate( Header.PathCount * sizeof(gePath*) );
01927 
01928         if ( M->Leaf.PathArray == NULL )
01929                 {       
01930                         geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL);
01931                         return GE_TRUE;
01932                 }
01933 
01934         for (i=0; i<Header.PathCount; i++)
01935                 {
01936                         M->Leaf.PathArray[i] = gePath_CreateFromFile(pFile);
01937                         if (M->Leaf.PathArray[i] == NULL )
01938                                 {
01939                                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL); 
01940                                         return GE_FALSE; 
01941                                 }
01942                         M->Leaf.PathCount++;
01943                 }
01944         return GE_TRUE;
01945 }
01946 
01947 static geMotion *GENESISCC geMotion_CreateFromBinaryFile(geVFile *pFile)
01948 {
01949         uint32 u;       
01950         geBoolean MaintainNames;
01951         int NodeType;
01952         int NameLength;
01953         geMotion *M;
01954 
01955         assert( pFile != NULL );
01956 
01957         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
01958                 {
01959                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01960                         return NULL;
01961                 }
01962         if (u!=MOTION_FILE_VERSION)
01963                 {
01964                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01965                         return NULL;
01966                 }
01967         if(geVFile_Read(pFile, &u, sizeof(u)) == GE_FALSE)
01968                 {
01969                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
01970                         return NULL;
01971                 }
01972 
01973         if (u & (1<<16)) 
01974                 {
01975                         MaintainNames = GE_TRUE;
01976                 }
01977         else
01978                 {
01979                         MaintainNames = GE_FALSE;
01980                 }
01981 
01982         NameLength = (u & 0xFFFF);
01983         NodeType   = (u >> 24);
01984         M = geMotion_Create(MaintainNames);
01985         if ( M == NULL )
01986                 {
01987                         geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL);
01988                         return NULL;
01989                 }
01990         if (NameLength>0)
01991                 {
01992                         M->Name = geRam_Allocate(NameLength);
01993                         if ( M->Name == NULL )
01994                                 {
01995                                         geErrorLog_Add(ERR_MOTION_CREATE_ENOMEM, NULL);
01996                                         geMotion_Destroy(&M);
01997                                         return NULL;
01998                                 }
01999                         if ( geVFile_Read (pFile, M->Name, NameLength ) == GE_FALSE )
02000                                 {
02001                                         geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
02002                                         geMotion_Destroy(&M);
02003                                         return NULL;
02004                                 }
02005                 }
02006         else
02007                 {
02008                         M->Name = NULL;
02009                 }
02010         switch (NodeType)
02011                 {
02012                         case (MOTION_NODE_UNDECIDED):
02013                                 break;
02014                         case (MOTION_NODE_BRANCH):
02015                                 if (geMotion_ReadBinaryBranch(M,pFile)==GE_FALSE)
02016                                         {
02017                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
02018                                                 geMotion_Destroy(&M);
02019                                                 return NULL;
02020                                         }
02021                                 break;
02022                         case (MOTION_NODE_LEAF):
02023                                 if (geMotion_ReadBinaryLeaf(M,pFile)==GE_FALSE)
02024                                         {
02025                                                 geErrorLog_Add( ERR_MOTION_FILE_READ , NULL);
02026                                                 geMotion_Destroy(&M);
02027                                                 return NULL;
02028                                         }
02029                                 break;
02030                         default:
02031                                 assert(0);
02032                                 break;
02033                 }
02034         return M;
02035 }
02036 
02037 
02038 static geBoolean GENESISCC geMotion_WriteBinaryLeaf(const geMotion *M, geVFile *pFile)
02039 {
02040         int i;
02041         geMotion_BinaryFileLeafHeader Header;
02042 
02043         #define MOTION_LEAF_EVENTS_FLAG    (1)
02044         #define MOTION_LEAF_NAMEARRAY_FLAG (2)
02045 
02046         assert( M != NULL );
02047         assert( pFile != NULL );
02048         assert( M->NodeType == MOTION_NODE_LEAF);
02049         assert( geMotion_IsValid(M) != GE_FALSE );
02050 
02051         Header.PathCount = M->Leaf.PathCount;
02052         Header.NameChecksum = M->Leaf.NameChecksum;
02053         Header.Flags = 0;
02054 
02055         if (M->Leaf.Events != NULL)
02056                 {
02057                         Header.Flags |= MOTION_LEAF_EVENTS_FLAG;
02058                 }
02059 
02060         if (M->Leaf.NameArray != NULL)
02061                 {
02062                         Header.Flags |= MOTION_LEAF_NAMEARRAY_FLAG;
02063                 }
02064                 
02065                 
02066         if (geVFile_Write(pFile, &Header, sizeof(geMotion_BinaryFileLeafHeader)) == GE_FALSE)
02067                 {
02068                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
02069                         return GE_FALSE; 
02070                 }
02071                         
02072 
02073         if (Header.Flags & MOTION_LEAF_EVENTS_FLAG)
02074                 {
02075                         if (geTKEvents_WriteToBinaryFile(M->Leaf.Events,pFile)==GE_FALSE)
02076                                 {
02077                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
02078                                         return GE_FALSE; 
02079                                 }
02080                 }
02081 
02082         
02083         if (Header.Flags & MOTION_LEAF_NAMEARRAY_FLAG)
02084                 {
02085                         if (geStrBlock_WriteToBinaryFile(M->Leaf.NameArray,pFile)==GE_FALSE)
02086                                 {
02087                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
02088                                         return GE_FALSE; 
02089                                 }
02090                 }
02091 
02092         for (i=0; i<M->Leaf.PathCount; i++)
02093                 {
02094                         if (gePath_WriteToBinaryFile(M->Leaf.PathArray[i],pFile) == GE_FALSE)
02095                                 {
02096                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL); 
02097                                         return GE_FALSE; 
02098                                 }
02099                 }
02100         return GE_TRUE;
02101 }
02102 
02103 static geBoolean GENESISCC geMotion_WriteBinaryBranch(const geMotion *M, geVFile *pFile)
02104 {
02105         assert( M != NULL );
02106         assert( pFile != NULL );
02107         assert( M->NodeType == MOTION_NODE_BRANCH);
02108         assert( geMotion_IsValid(M) != GE_FALSE );
02109         #pragma message("finish this")
02110         return GE_FALSE;
02111 }
02112 
02113 
02114 GENESISAPI geBoolean GENESISCC geMotion_WriteToBinaryFile(const geMotion *M,geVFile *pFile)
02115 {
02116         uint32 u;
02117 
02118         assert( M != NULL );
02119         assert( pFile != NULL );
02120         assert( geMotion_IsValid(M) != GE_FALSE );
02121 
02122 
02123         // Write the format flag
02124         u = MOTION_BIN_FILE_TYPE;
02125         if(geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE)
02126                 {
02127                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
02128                         return GE_FALSE;
02129                 }
02130 
02131         u = MOTION_FILE_VERSION;
02132         if (geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE)
02133                 {
02134                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
02135                         return GE_FALSE;
02136                 }
02137         if ( M->Name != NULL )
02138                 {
02139                         u = strlen(M->Name)+1;
02140                 }
02141         else
02142                 {
02143                         u = 0;
02144                 }
02145         assert( u < 0xFFFF );
02146         
02147         if (M->MaintainNames != GE_FALSE)
02148                 {
02149                         u |= (1<<16);
02150                 }
02151         assert( M->NodeType < 0xFF );
02152         u |= (M->NodeType << 24);
02153         if (geVFile_Write(pFile, &u, sizeof(u)) == GE_FALSE)
02154                 {
02155                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
02156                         return GE_FALSE;
02157                 }
02158         if ((u&0xFFFF) > 0)
02159                 {
02160                         if (geVFile_Write(pFile, M->Name, (u&0xFFFF)) == GE_FALSE)
02161                                 {
02162                                         geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
02163                                         return GE_FALSE;
02164                                 }
02165                 }
02166 
02167         switch (M->NodeType)
02168                 {
02169                         case (MOTION_NODE_UNDECIDED):
02170                                 break;
02171                         case (MOTION_NODE_BRANCH):
02172                                 if (geMotion_WriteBinaryBranch(M,pFile)==GE_FALSE)
02173                                         {
02174                                                 geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
02175                                                 return GE_FALSE;
02176                                         }
02177                                 break;
02178                         case (MOTION_NODE_LEAF):
02179                                 if (geMotion_WriteBinaryLeaf(M,pFile)==GE_FALSE)
02180                                         {
02181                                                 geErrorLog_Add( ERR_MOTION_FILE_WRITE , NULL);
02182                                                 return GE_FALSE;
02183                                         }
02184                                 break;
02185                         default:
02186                                 assert(0);
02187                                 break;
02188                 }
02189         return GE_TRUE;
02190 }

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