/tags/JSTUDIO3D_2_5_beta_1/source/Engine/JetEngine/Actor/Actor.cpp

# · C++ · 2320 lines · 1760 code · 431 blank · 129 comment · 439 complexity · 2c32d4b0c58890f14c019605bb4c175f MD5 · raw file

Large files are truncated click here to view the full file

  1. /****************************************************************************************/
  2. /* ACTOR.C */
  3. /* */
  4. /* Authors: Mike Sandige */
  5. /* Aaron Oneal (Incarnadine) - aoneal@ij.net */
  6. /* Description: Actor implementation */
  7. /* */
  8. /* The contents of this file are subject to the Jet3D Public License */
  9. /* Version 1.02 (the "License"); you may not use this file except in */
  10. /* compliance with the License. You may obtain a copy of the License at */
  11. /* http://www.jet3d.com */
  12. /* */
  13. /* Software distributed under the License is distributed on an "AS IS" */
  14. /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
  15. /* the License for the specific language governing rights and limitations */
  16. /* under the License. */
  17. /* */
  18. /* The Original Code is Jet3D, released December 12, 1999. */
  19. /* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */
  20. /* */
  21. /****************************************************************************************/
  22. /*
  23. TODO:
  24. make cued motions keyed to a 'root' bone. Register the root bone, and then
  25. all requests are relative to that bone, rather than the current 'anchor' point.
  26. actually, this doesn't really change much, just _AnimationCue() - and it allows
  27. a more efficient _TestStep()
  28. convert BoundingBoxMinCorner, BoundingBoxMaxCorner to use extbox.
  29. */
  30. #include <assert.h>
  31. #include <string.h> // _stricmp()
  32. #include <malloc.h> // free
  33. #include <math.h>
  34. #include "Actor.h"
  35. #include "Ram.h"
  36. #include "Puppet.h"
  37. #include "Body.h"
  38. #include "Motion.h"
  39. #include "Errorlog.h"
  40. #include "StrBlock.h"
  41. #include "Log.h"
  42. #include "Actor._h"
  43. #ifdef WIN32
  44. #pragma warning ( disable : 4115 )
  45. #include <windows.h>
  46. #pragma warning ( default : 4115 )
  47. #endif
  48. #ifdef BUILD_BE
  49. #define _stricmp strcasecmp
  50. #endif
  51. #define ACTOR_MOTIONS_MAX 0x0FFFF // really arbitrary. just for sanity checking
  52. #define ACTOR_CUES_MAX 0x0FFFF // arbitrary.
  53. /*
  54. typedef struct ActorObj {
  55. char *ActorDefName, *MotionName;
  56. jeBoolean CollisionExtBoxDisplay;
  57. jeExtBox CollisionExtBox;
  58. jeBoolean RenderExtBoxDisplay;
  59. jeExtBox RenderHintExtBox;
  60. char **MotionList;
  61. int MotionListSize;
  62. jeMotion *Motion;
  63. float MotionTime;
  64. float ScaleX,ScaleY,ScaleZ;
  65. float MotionTimeScale;
  66. jeWorld *World;
  67. jeEngine *Engine;
  68. jeResourceMgr *ResourceMgr;
  69. } ActorObj;*/
  70. // these are useful globals to monitor resources
  71. int jeActor_Count = 0;
  72. int jeActor_RefCount = 0;
  73. int jeActor_DefCount = 0;
  74. int jeActor_DefRefCount = 0;
  75. // [MacroArt::Begin]
  76. // Thanks Dee(cryscan@home.net)
  77. JETAPI float JETCC jeActor_GetAlpha(const jeActor *A)
  78. {
  79. assert( A != NULL ) ;
  80. assert( A->Puppet != NULL ) ;
  81. return jePuppet_GetAlpha(A->Puppet);
  82. }
  83. JETAPI void JETCC jeActor_SetAlpha(jeActor *A, float Alpha)
  84. {
  85. assert( A != NULL ) ;
  86. assert( A->Puppet != NULL ) ;
  87. jePuppet_SetAlpha( A->Puppet, Alpha ) ;
  88. }
  89. // [MacroArt::End]
  90. // returns number of actors that are currently created.
  91. JETAPI int32 JETCC jeActor_GetCount(void)
  92. {
  93. return jeActor_Count;
  94. }
  95. JETAPI jeBoolean JETCC jeActor_IsValid(const jeActor *A)
  96. {
  97. if (A==NULL)
  98. return JE_FALSE;
  99. if(A->ActorDefinition)
  100. {
  101. if (A->Pose == NULL)
  102. return JE_FALSE;
  103. if (A->CueMotion == NULL)
  104. return JE_FALSE;
  105. if (jeActor_DefIsValid(A->ActorDefinition)==JE_FALSE)
  106. return JE_FALSE;
  107. if (jeBody_IsValid(A->ActorDefinition->Body) == JE_FALSE )
  108. return JE_FALSE;
  109. }
  110. return JE_TRUE;
  111. }
  112. JETAPI jeBoolean JETCC jeActor_DefIsValid(const jeActor_Def *A)
  113. {
  114. if (A==NULL)
  115. return JE_FALSE;
  116. if (A->ValidityCheck != A)
  117. return JE_FALSE;
  118. return JE_TRUE;
  119. }
  120. static jeBoolean JETCF jeActor_GetBoneIndex(const jeActor *A, const char *BoneName, int *BoneIndex)
  121. {
  122. jeXForm3d Dummy;
  123. int ParentBoneIndex;
  124. assert( jeActor_IsValid(A) != JE_FALSE);
  125. assert( jeActor_DefIsValid(A->ActorDefinition) != JE_FALSE );
  126. assert( jeBody_IsValid(A->ActorDefinition->Body) != JE_FALSE );
  127. assert( BoneIndex != NULL );
  128. if ( BoneName != NULL )
  129. {
  130. if (jeBody_GetBoneByName(A->ActorDefinition->Body,
  131. BoneName,
  132. BoneIndex,
  133. &Dummy,
  134. &ParentBoneIndex) ==JE_FALSE)
  135. {
  136. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_GetBoneIndex: Named bone not found:", BoneName);
  137. return JE_FALSE;
  138. }
  139. }
  140. else
  141. {
  142. *BoneIndex = JE_POSE_ROOT_JOINT;
  143. }
  144. return JE_TRUE;
  145. }
  146. JETAPI jeActor_Def *JETCC jeActor_GetActorDef(const jeActor *A)
  147. {
  148. assert( jeActor_DefIsValid(A->ActorDefinition) != JE_FALSE );
  149. return A->ActorDefinition;
  150. }
  151. JETAPI void JETCC jeActor_DefCreateRef(jeActor_Def *A)
  152. {
  153. assert( jeActor_DefIsValid(A) != JE_FALSE );
  154. A->RefCount++;
  155. jeActor_DefRefCount++;
  156. }
  157. JETAPI jeActor_Def *JETCC jeActor_DefCreate(void)
  158. {
  159. jeActor_Def *Ad;
  160. Ad = JE_RAM_ALLOCATE_STRUCT_CLEAR( jeActor_Def );
  161. if ( Ad == NULL )
  162. {
  163. jeErrorLog_Add( JE_ERR_MEMORY_RESOURCE,"jeActor_DefCreateRef: Failed to allocate Actor_Def");
  164. return NULL;
  165. }
  166. Ad->Body = NULL;
  167. Ad->MotionCount = 0;
  168. Ad->MotionArray = NULL;
  169. Ad->ValidityCheck = Ad;
  170. Ad->RefCount = 0;
  171. jeActor_DefCount++;
  172. return Ad;
  173. }
  174. JETAPI void JETCC jeActor_CreateRef(jeActor *Actor)
  175. {
  176. assert( jeActor_IsValid(Actor) );
  177. Actor->RefCount ++;
  178. jeActor_RefCount++;
  179. }
  180. JETAPI jeActor * JETCC jeActor_CreateFromDef(jeActor_Def *ActorDefinition)
  181. {
  182. jeActor *A;
  183. A = JE_RAM_ALLOCATE_STRUCT_CLEAR( jeActor );
  184. if ( A == NULL )
  185. {
  186. jeErrorLog_Add( JE_ERR_MEMORY_RESOURCE , "jeActor_Create: Failed to allocate jeActor struct");
  187. return NULL;
  188. }
  189. A->Puppet = NULL;
  190. A->Pose = NULL;
  191. A->CueMotion = NULL;
  192. A->ActorDefinition = NULL;
  193. A->RefCount = 0;
  194. A->CanFree = JE_TRUE;
  195. jeExtBox_Set(&(A->CollisionExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
  196. jeExtBox_Set(&(A->RenderHintExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
  197. jeXForm3d_SetIdentity(&A->Xf);
  198. jeActor_Count++;
  199. if(ActorDefinition != NULL)
  200. jeActor_SetActorDef(A,ActorDefinition);
  201. return A;
  202. }
  203. JETAPI jeActor *JETCC jeActor_Create()
  204. {
  205. jeActor *A;
  206. A = JE_RAM_ALLOCATE_STRUCT_CLEAR( jeActor );
  207. if ( A == NULL )
  208. {
  209. jeErrorLog_Add( JE_ERR_MEMORY_RESOURCE , "jeActor_Create: Failed to allocate jeActor struct");
  210. return NULL;
  211. }
  212. A->Puppet = NULL;
  213. A->Pose = NULL;
  214. A->CueMotion = NULL;
  215. A->ActorDefinition = NULL;
  216. A->RefCount = 0;
  217. A->CanFree = JE_TRUE;
  218. A->RenderNextTime = JE_TRUE;
  219. InitializeCriticalSection(&A->RenderLock);
  220. jeExtBox_Set(&(A->CollisionExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
  221. jeExtBox_Set(&(A->RenderHintExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
  222. jeXForm3d_SetIdentity(&A->Xf);
  223. jeActor_Count++;
  224. return A;
  225. }
  226. JETAPI jeBoolean JETCC jeActor_DefDestroy(jeActor_Def **pActorDefinition)
  227. {
  228. int i;
  229. jeActor_Def *Ad;
  230. assert( pActorDefinition != NULL );
  231. assert( *pActorDefinition != NULL );
  232. assert( jeActor_DefIsValid( *pActorDefinition ) != JE_FALSE );
  233. Ad = *pActorDefinition;
  234. if (Ad->RefCount > 0)
  235. {
  236. Ad->RefCount--;
  237. jeActor_DefRefCount--;
  238. return JE_FALSE;
  239. }
  240. if (Ad->Body != NULL)
  241. {
  242. jeBody_Destroy( &(Ad->Body) );
  243. Ad->Body = NULL;
  244. }
  245. if (Ad->MotionArray != NULL)
  246. {
  247. for (i=0; i<Ad->MotionCount; i++)
  248. {
  249. if (Ad->MotionArray[i]!=NULL)
  250. {
  251. jeMotion_Destroy( &(Ad->MotionArray[i]) );
  252. }
  253. Ad->MotionArray[i] = NULL;
  254. }
  255. jeRam_Free( Ad->MotionArray );
  256. Ad->MotionArray = NULL;
  257. }
  258. Ad->MotionCount = 0;
  259. jeRam_Free(*pActorDefinition);
  260. *pActorDefinition = NULL;
  261. jeActor_DefCount--;
  262. return JE_TRUE;
  263. }
  264. JETAPI jeBoolean JETCC jeActor_Destroy(jeActor **pA)
  265. {
  266. jeActor *A;
  267. jeChain_Link *Link;
  268. assert( pA != NULL );
  269. assert( *pA != NULL );
  270. assert( jeActor_IsValid(*pA) != JE_FALSE );
  271. A = *pA;
  272. if (A->RefCount > 0)
  273. {
  274. A->RefCount --;
  275. jeActor_RefCount--;
  276. return JE_FALSE;
  277. }
  278. if (A->Puppet != NULL)
  279. {
  280. jePuppet_Destroy( &(A->Puppet) );
  281. A->Puppet = NULL;
  282. }
  283. if ( A->Pose != NULL )
  284. {
  285. jePose_Destroy( &( A->Pose ) );
  286. A->Pose = NULL;
  287. }
  288. if ( A->CueMotion != NULL )
  289. {
  290. jeMotion_Destroy(&(A->CueMotion));
  291. A->CueMotion = NULL;
  292. }
  293. // destroy bone collision list -- Incarnadine
  294. if(A->BoneCollisionChain != NULL)
  295. {
  296. for (Link = jeChain_GetFirstLink(A->BoneCollisionChain); Link; Link = jeChain_LinkGetNext(Link))
  297. {
  298. // Icestorm: Added BoneExtBoxes
  299. jeCollisionBone *Bone;
  300. Bone = (jeCollisionBone*)jeChain_LinkGetLinkData( Link );
  301. if(Bone)
  302. {
  303. free(Bone->BoneName);
  304. jeRam_Free(Bone->CurrExtBox);
  305. jeRam_Free(Bone->PrevExtBox);
  306. jeRam_Free(Bone);
  307. }
  308. }
  309. // destroy object chain
  310. jeChain_Destroy( &( A->BoneCollisionChain ) );
  311. A->BoneCollisionChain = NULL;
  312. }
  313. if(A->ActorDefinition != NULL)
  314. {
  315. jeActor_DefDestroy(&(A->ActorDefinition));
  316. A->ActorDefinition = NULL;
  317. }
  318. if(A->Object != NULL)
  319. {
  320. jeRam_Free(A->Object);
  321. A->Object = NULL;
  322. }
  323. DeleteCriticalSection(&A->RenderLock);
  324. if(A->CanFree == JE_TRUE)
  325. {
  326. jeActor_Count--;
  327. jeRam_Free(*pA);
  328. *pA = NULL;
  329. }
  330. return JE_TRUE;
  331. }
  332. // Incarnadine
  333. // INCNOTE: This function isn't right, it needs to totally kill the actor
  334. // Do a new create basically. Look into making a separate function
  335. // that calls the old actor create function.
  336. JETAPI void JETCC jeActor_SetActorDef(jeActor *A, jeActor_Def *Def)
  337. {
  338. ActorObj *pObj;
  339. assert(A);
  340. assert(Def);
  341. assert( jeActor_DefIsValid(Def) != JE_FALSE );
  342. assert( jeBody_IsValid(Def->Body) != JE_FALSE );
  343. if(A->Pose != NULL)
  344. {
  345. pObj = A->Object;
  346. A->Object = NULL;
  347. A->CanFree = JE_FALSE;
  348. jeActor_Destroy(&A);
  349. A->CanFree = JE_TRUE;
  350. A->Object = pObj;
  351. }
  352. A->ActorDefinition = Def;
  353. jeExtBox_Set(&(A->CollisionExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
  354. jeExtBox_Set(&(A->RenderHintExtBox), 0.0f,0.0f,0.0f,0.0f,0.0f,0.0f);
  355. jeXForm3d_SetIdentity(&A->Xf);
  356. A->Pose = jePose_Create();
  357. if (A->Pose == NULL)
  358. {
  359. jeErrorLog_Add(JE_ERR_MEMORY_RESOURCE , "jeActor_Create: Failed to allocate Pose");
  360. goto ActorCreateFailure;
  361. }
  362. A->CueMotion = jeMotion_Create(JE_TRUE);
  363. A->BlendingType = JE_ACTOR_BLEND_HERMITE;
  364. A->BoundingBoxCenterBoneIndex = JE_POSE_ROOT_JOINT;
  365. A->RenderHintExtBoxCenterBoneIndex = JE_POSE_ROOT_JOINT;
  366. A->RenderHintExtBoxEnabled = JE_FALSE;
  367. A->StepBoneIndex = JE_POSE_ROOT_JOINT;
  368. if (A->CueMotion == NULL)
  369. {
  370. jeErrorLog_Add(JE_ERR_MEMORY_RESOURCE , "jeActor_Create: Failed to allocate CueMotion");
  371. goto ActorCreateFailure;
  372. }
  373. A->BoneCollisionChain = jeChain_Create(); // Incarnadine
  374. A->CollisionFlags = COLLIDE_SOLID; // Incarnadine
  375. A->LastUsedCollisionBone=NULL; // Icestorm
  376. A->LastUsedCollisionBoneName=NULL; // Icestorm
  377. A->needsRelighting = JE_TRUE;
  378. assert( jeActor_IsValid(A) != JE_FALSE );
  379. {
  380. int i;
  381. int BoneCount;
  382. BoneCount = jeBody_GetBoneCount(A->ActorDefinition->Body);
  383. for (i=0; i<BoneCount; i++)
  384. {
  385. const char *Name;
  386. jeXForm3d Attachment;
  387. int ParentBone;
  388. int Index;
  389. jeBody_GetBone( A->ActorDefinition->Body, i, &Name,&Attachment, &ParentBone );
  390. if (jePose_AddJoint( A->Pose,
  391. ParentBone,Name,&Attachment,&Index)==JE_FALSE)
  392. {
  393. jeErrorLog_Add(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_Create: jePose_AddJoint failed");
  394. A->ActorDefinition;
  395. return;
  396. }
  397. }
  398. }
  399. jeActor_DefCreateRef(Def);
  400. if(A->Object && A->Object->Engine)
  401. jeActor_AttachEngine(A, A->Object->Engine );
  402. return;
  403. ActorCreateFailure:
  404. if ( A!= NULL)
  405. {
  406. if (A->Pose != NULL)
  407. jePose_Destroy(&(A->Pose));
  408. if (A->CueMotion != NULL)
  409. jeMotion_Destroy(&(A->CueMotion));
  410. jeRam_Free( A );
  411. }
  412. }
  413. JETAPI jeBoolean JETCC jeActor_SetBody( jeActor_Def *ActorDefinition, jeBody *BodyGeometry)
  414. {
  415. assert( jeBody_IsValid(BodyGeometry) != JE_FALSE );
  416. if (ActorDefinition->RefCount > 0)
  417. {
  418. jeErrorLog_Add(JE_ERR_BAD_PARAMETER,"jeActor_SetBody: ActorDef in use, can't modify body");
  419. return JE_FALSE;
  420. }
  421. if (ActorDefinition->Body != NULL)
  422. {
  423. jeBody_Destroy( &(ActorDefinition->Body) );
  424. }
  425. ActorDefinition->Body = BodyGeometry;
  426. return JE_TRUE;
  427. }
  428. #pragma message ("consider removing this and related parameters to setpose")
  429. JETAPI void JETCC jeActor_SetBlendingType( jeActor *A, jeActor_BlendingType BlendingType )
  430. {
  431. assert( jeActor_IsValid(A) != JE_FALSE );
  432. assert( (BlendingType == JE_ACTOR_BLEND_LINEAR) ||
  433. (BlendingType == JE_ACTOR_BLEND_HERMITE) );
  434. if (BlendingType == JE_ACTOR_BLEND_LINEAR)
  435. {
  436. A->BlendingType = (jeActor_BlendingType)JE_POSE_BLEND_LINEAR;
  437. }
  438. else
  439. {
  440. A->BlendingType = (jeActor_BlendingType)JE_POSE_BLEND_HERMITE;
  441. }
  442. }
  443. jeVFile *jeActor_DefGetFileContext(const jeActor_Def *A)
  444. {
  445. assert( jeActor_DefIsValid(A) != JE_FALSE );
  446. return A->TextureFileContext;
  447. }
  448. JETAPI jeBoolean JETCC jeActor_AddMotion(jeActor_Def *Ad, jeMotion *NewMotion, int32 *Index)
  449. {
  450. jeMotion **NewMArray;
  451. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  452. assert( NewMotion != NULL );
  453. assert( Index != NULL );
  454. if (Ad->MotionCount >= ACTOR_MOTIONS_MAX)
  455. {
  456. jeErrorLog_Add(JE_ERR_LIST_FULL,"jeActor_AddMotion: Too many motions");
  457. return JE_FALSE;
  458. }
  459. NewMArray = JE_RAM_REALLOC_ARRAY( Ad->MotionArray, jeMotion*, Ad->MotionCount +1 );
  460. if ( NewMArray == NULL )
  461. {
  462. jeErrorLog_Add(JE_ERR_MEMORY_RESOURCE,"jeActor_AddMotion: Failed to reallocate motion array");
  463. return JE_FALSE;
  464. }
  465. Ad->MotionArray = NewMArray;
  466. Ad->MotionArray[Ad->MotionCount]= NewMotion;
  467. Ad->MotionCount++;
  468. *Index = Ad->MotionCount;
  469. return JE_TRUE;
  470. };
  471. JETAPI void JETCC jeActor_ClearPose(jeActor *A, const jeXForm3d *Transform)
  472. {
  473. assert( jeActor_IsValid(A) != JE_FALSE );
  474. assert ( (Transform==NULL) || (jeXForm3d_IsOrthonormal(Transform) != JE_FALSE) );
  475. jePose_Clear( A->Pose ,Transform);
  476. A->Xf = *Transform; //Incarnadine
  477. A->needsRelighting = JE_TRUE;
  478. }
  479. JETAPI void JETCC jeActor_SetPose(jeActor *A, const jeMotion *M,
  480. jeFloat Time, const jeXForm3d *Transform)
  481. {
  482. assert( jeActor_IsValid(A) != JE_FALSE );
  483. assert( M != NULL );
  484. assert ( (Transform==NULL) || (jeXForm3d_IsOrthonormal(Transform) != JE_FALSE) );
  485. jePose_SetMotion( A->Pose,M,Time,Transform);
  486. A->Xf = *Transform; //Incarnadine
  487. A->needsRelighting = JE_TRUE;
  488. }
  489. JETAPI void JETCC jeActor_BlendPose(jeActor *A, const jeMotion *M,
  490. jeFloat Time,
  491. const jeXForm3d *Transform,
  492. jeFloat BlendAmount)
  493. {
  494. assert( jeActor_IsValid(A) != JE_FALSE );
  495. assert( M != NULL );
  496. assert ( (Transform==NULL) || (jeXForm3d_IsOrthonormal(Transform) != JE_FALSE) );
  497. jePose_BlendMotion( A->Pose,M,Time,Transform,
  498. BlendAmount,(jePose_BlendingType)A->BlendingType);
  499. A->Xf = *Transform; //Incarnadine
  500. A->needsRelighting = JE_TRUE;
  501. }
  502. JETAPI int32 JETCC jeActor_GetMotionCount(const jeActor_Def *Ad)
  503. {
  504. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  505. return Ad->MotionCount;
  506. }
  507. JETAPI jeMotion *JETCC jeActor_GetMotionByIndex(const jeActor_Def *Ad, int32 Index )
  508. {
  509. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  510. assert( Index >= 0 );
  511. assert( Index < Ad->MotionCount );
  512. assert( Ad->MotionArray != NULL );
  513. return Ad->MotionArray[Index];
  514. }
  515. JETAPI jeMotion *JETCC jeActor_GetMotionByName(const jeActor_Def *Ad, const char *Name )
  516. {
  517. int i;
  518. const char *TestName;
  519. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  520. assert( Name != NULL );
  521. for (i=0; i<Ad->MotionCount; i++)
  522. {
  523. TestName = jeMotion_GetName(Ad->MotionArray[i]);
  524. if (TestName != NULL)
  525. {
  526. if (_stricmp(TestName,Name)==0) // Case insensitive compare -- Incarnadine
  527. return Ad->MotionArray[i];
  528. }
  529. }
  530. return NULL;
  531. }
  532. JETAPI const char *JETCC jeActor_GetMotionName(const jeActor_Def *Ad, int32 Index )
  533. {
  534. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  535. assert( Index >= 0 );
  536. assert( Index < Ad->MotionCount );
  537. assert( Ad->MotionArray != NULL );
  538. return jeMotion_GetName(Ad->MotionArray[Index]);
  539. }
  540. JETAPI jeBody *JETCC jeActor_GetBody(const jeActor_Def *Ad)
  541. {
  542. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  543. return Ad->Body;
  544. }
  545. #pragma message ("consider removing the function: jeActor_DefHasBoneNamed")
  546. // Returns JE_TRUE if the actor definition has a bone named 'Name'
  547. JETAPI jeBoolean JETCC jeActor_DefHasBoneNamed(const jeActor_Def *Ad, const char *Name )
  548. {
  549. int DummyIndex,DummyParent;
  550. jeXForm3d DummyAttachment;
  551. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  552. assert( Name != NULL );
  553. if (jeBody_GetBoneByName(jeActor_GetBody(Ad),Name,
  554. &DummyIndex, &DummyAttachment, &DummyParent ) == JE_FALSE )
  555. {
  556. return JE_FALSE;
  557. }
  558. return JE_TRUE;
  559. }
  560. #define JE_ACTOR_BODY_NAME "Body"
  561. #define JE_ACTOR_HEADER_NAME "Header"
  562. #define JE_MOTION_DIRECTORY_NAME "Motions"
  563. #define ACTOR_FILE_TYPE 0x52544341 // 'ACTR'
  564. #define ACTOR_FILE_VERSION 0x00F2 // Restrict version to 16 bits
  565. static jeActor_Def * JETCF jeActor_DefCreateHeader(jeVFile *pFile, jeBoolean *HasBody)
  566. {
  567. uint32 u;
  568. uint32 version;
  569. jeActor_Def *Ad;
  570. assert( pFile != NULL );
  571. assert( HasBody != NULL );
  572. if( ! jeVFile_Read(pFile, &u, sizeof(u)) )
  573. { jeErrorLog_Add( JE_ERR_FILEIO_READ , "jeActor_DefCreateHeader - Failed to read header tag"); jeActor_DefDestroy(&Ad); return NULL;}
  574. if (u != ACTOR_FILE_TYPE)
  575. { jeErrorLog_Add( JE_ERR_FILEIO_FORMAT , "jeActor_DefCreateHeader - Failed to recognize format"); return NULL;}
  576. if(jeVFile_Read(pFile, &version, sizeof(version)) == JE_FALSE)
  577. { jeErrorLog_Add( JE_ERR_FILEIO_READ , "jeActor_DefCreateHeader - Read Failed"); return NULL;}
  578. if ( (version != ACTOR_FILE_VERSION) )
  579. { jeErrorLog_Add( JE_ERR_FILEIO_VERSION , "jeActor_DefCreateHeader - Bad version"); return NULL;}
  580. Ad = jeActor_DefCreate();
  581. if (Ad==NULL)
  582. { jeErrorLog_Add( JE_ERR_MEMORY_RESOURCE, "jeActor_DefCreateHeader - Failed to create Def struct"); return NULL; }
  583. if(jeVFile_Read(pFile, HasBody, sizeof(*HasBody)) == JE_FALSE)
  584. { jeErrorLog_Add( JE_ERR_FILEIO_READ , "jeActor_DefCreateHeader - Read Failed"); jeActor_DefDestroy(&Ad); return NULL;}
  585. if(jeVFile_Read(pFile, &(Ad->MotionCount), sizeof(Ad->MotionCount)) == JE_FALSE)
  586. { jeErrorLog_Add( JE_ERR_FILEIO_READ , "jeActor_DefCreateHeader - Read failed"); jeActor_DefDestroy(&Ad); return NULL;}
  587. return Ad;
  588. }
  589. static jeBoolean JETCF jeActor_DefWriteHeader(const jeActor_Def *Ad, jeVFile *pFile)
  590. {
  591. uint32 u;
  592. jeBoolean Flag;
  593. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  594. assert( pFile != NULL );
  595. // Write the format flag
  596. u = ACTOR_FILE_TYPE;
  597. if(jeVFile_Write(pFile, &u, sizeof(u)) == JE_FALSE)
  598. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteHeader - Write failed"); return JE_FALSE; }
  599. u = ACTOR_FILE_VERSION;
  600. if(jeVFile_Write(pFile, &u, sizeof(u)) == JE_FALSE)
  601. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteHeader - Write failed"); return JE_FALSE;}
  602. if (Ad->Body != NULL)
  603. Flag = JE_TRUE;
  604. else
  605. Flag = JE_FALSE;
  606. if(jeVFile_Write(pFile, &Flag, sizeof(Flag)) == JE_FALSE)
  607. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteHeader - Write failed"); return JE_FALSE;}
  608. if(jeVFile_Write(pFile, &(Ad->MotionCount), sizeof(Ad->MotionCount)) == JE_FALSE)
  609. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteHeader - Write failed"); return JE_FALSE;}
  610. #ifdef COUNT_HEADER_SIZES
  611. Header_Sizes += 16;
  612. #endif
  613. return JE_TRUE;
  614. }
  615. JETAPI jeActor_Def *JETCC jeActor_DefCreateFromFile(jeVFile *pFile)
  616. {
  617. int i;
  618. jeActor_Def *Ad = NULL;
  619. jeVFile *VFile = NULL;
  620. jeVFile *SubFile = NULL;
  621. jeVFile *MotionDirectory = NULL;
  622. jeBoolean HasBody = JE_FALSE;
  623. jeBody * Body = NULL;
  624. assert( pFile != NULL );
  625. VFile = jeVFile_OpenNewSystem(pFile,JE_VFILE_TYPE_VIRTUAL, NULL,
  626. NULL, JE_VFILE_OPEN_DIRECTORY | JE_VFILE_OPEN_READONLY);
  627. if (VFile == NULL)
  628. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefCreateFromFile - Failed to open actor vfile system"); goto CreateError;}
  629. SubFile = jeVFile_Open(VFile,JE_ACTOR_HEADER_NAME,JE_VFILE_OPEN_READONLY);
  630. if (SubFile == NULL)
  631. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefCreateFromFile - Failed to open header subfile"); goto CreateError;}
  632. #if 1
  633. {
  634. jeVFile * HFile;
  635. HFile = jeVFile_GetHintsFile(SubFile);
  636. if ( ! HFile ) // <> backwards compatibility
  637. HFile = SubFile;
  638. Ad = jeActor_DefCreateHeader(HFile, &HasBody);
  639. }
  640. #else
  641. Ad = jeActor_DefCreateHeader( SubFile, &HasBody);
  642. #endif
  643. if (Ad == NULL)
  644. {
  645. jeErrorLog_Add( JE_ERR_SUBSYSTEM_FAILURE, "jeActor_DefCreateFromFile -");
  646. goto CreateError;
  647. }
  648. if (!jeVFile_Close(SubFile))
  649. {
  650. jeErrorLog_Add( JE_ERR_FILEIO_CLOSE ,"jeActor_DefCreateFromFile - Failed to close header subfile");
  651. goto CreateError;
  652. }
  653. Ad->TextureFileContext = VFile;
  654. assert(Ad->TextureFileContext);
  655. if (HasBody != JE_FALSE)
  656. {
  657. SubFile = jeVFile_Open(VFile,JE_ACTOR_BODY_NAME,JE_VFILE_OPEN_READONLY);
  658. if (SubFile == NULL)
  659. { jeErrorLog_Add( JE_ERR_FILEIO_READ , "jeActor_DefCreateFromFile - Read failed"); goto CreateError;}
  660. Body = jeBody_CreateFromFile(SubFile);
  661. if (Body == NULL)
  662. {
  663. jeErrorLog_Add( JE_ERR_FILEIO_READ , "jeActor_DefCreateFromFile - Read failed");
  664. goto CreateError;
  665. }
  666. if (jeActor_SetBody(Ad,Body)==JE_FALSE)
  667. {
  668. jeErrorLog_Add( JE_ERR_SUBSYSTEM_FAILURE, "jeActor_DefCreateFromFile -");
  669. goto CreateError;
  670. }
  671. jeVFile_Close(SubFile);
  672. }
  673. MotionDirectory = jeVFile_Open(VFile,JE_MOTION_DIRECTORY_NAME,
  674. JE_VFILE_OPEN_DIRECTORY | JE_VFILE_OPEN_READONLY);
  675. if (MotionDirectory == NULL)
  676. { jeErrorLog_Add( JE_ERR_SUBSYSTEM_FAILURE,"jeActor_DefCreateFromFile -"); return NULL;}
  677. if (Ad->MotionCount>0)
  678. {
  679. Ad->MotionArray = JE_RAM_ALLOCATE_ARRAY( jeMotion*, Ad->MotionCount);
  680. if (Ad->MotionArray == NULL)
  681. { jeErrorLog_Add( JE_ERR_MEMORY_RESOURCE,"jeActor_DefCreateFromFile - Failed to allocate motion array"); return NULL; }
  682. for (i=0; i<Ad->MotionCount; i++)
  683. Ad->MotionArray[i] = NULL;
  684. for (i=0; i<Ad->MotionCount; i++)
  685. {
  686. char FName[1000];
  687. sprintf(FName,"%d",i);
  688. SubFile = jeVFile_Open(MotionDirectory,FName,JE_VFILE_OPEN_READONLY);
  689. if (SubFile == NULL)
  690. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN ,"jeActor_DefCreateFromFile - Failed to open motion subdirectory"); goto CreateError;}
  691. #if 0
  692. Ad->MotionArray[i] = jeMotion_CreateFromFile(SubFile);
  693. #else
  694. {
  695. jeVFile * LZFS;
  696. LZFS = jeVFile_OpenNewSystem(SubFile,JE_VFILE_TYPE_LZ, NULL, NULL,JE_VFILE_OPEN_READONLY);
  697. if ( !LZFS )
  698. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN ,"jeActor_DefCreateFromFile - Failed to open compressed vfile"); goto CreateError;}
  699. Ad->MotionArray[i] = jeMotion_CreateFromFile(LZFS);
  700. Log_Printf("Actor : Motions : ");
  701. if ( ! jeVFile_Close(LZFS) )
  702. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE ,"jeActor_DefCreateFromFile - Failed to close compressed vfile"); goto CreateError;}
  703. }
  704. #endif
  705. if (Ad->MotionArray[i] == NULL)
  706. { jeErrorLog_AddString( JE_ERR_SUBSYSTEM_FAILURE,"jeActor_DefCreateFromFile - Failed to read motion #",jeErrorLog_IntToString(i)); goto CreateError;}
  707. if (!jeVFile_Close(SubFile) )
  708. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE ,"jeActor_DefCreateFromFile - Failed to close sub motion file"); goto CreateError;}
  709. }
  710. }
  711. else
  712. {
  713. Ad->MotionArray = NULL;
  714. }
  715. if (!jeVFile_Close(MotionDirectory))
  716. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE ,"jeActor_DefCreateFromFile - Failed to close motion directory"); goto CreateError;}
  717. if (!jeVFile_Close(VFile))
  718. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE ,"jeActor_DefCreateFromFile - Failed to close actor vfile system"); goto CreateError;}
  719. return Ad;
  720. CreateError:
  721. if (SubFile != NULL)
  722. jeVFile_Close(SubFile);
  723. if (MotionDirectory != NULL)
  724. jeVFile_Close(MotionDirectory);
  725. if (VFile != NULL)
  726. jeVFile_Close(VFile);
  727. if (Ad != NULL)
  728. jeActor_DefDestroy(&Ad);
  729. return NULL;
  730. }
  731. JETAPI jeBoolean JETCC jeActor_DefWriteToFile(const jeActor_Def *Ad, jeVFile *pFile)
  732. {
  733. int i;
  734. jeVFile *VFile;
  735. jeVFile *SubFile;
  736. jeVFile *MotionDirectory;
  737. assert( jeActor_DefIsValid(Ad) != JE_FALSE );
  738. assert( pFile != NULL );
  739. VFile = jeVFile_OpenNewSystem(pFile,JE_VFILE_TYPE_VIRTUAL, NULL,
  740. NULL, JE_VFILE_OPEN_DIRECTORY | JE_VFILE_OPEN_CREATE);
  741. if (VFile == NULL)
  742. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefWriteToFile - Failed to open actor vfile system"); goto WriteError;}
  743. SubFile = jeVFile_Open(VFile,JE_ACTOR_HEADER_NAME,JE_VFILE_OPEN_CREATE);
  744. if (SubFile == NULL)
  745. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefWriteToFile - Failed to open actor header subfile"); goto WriteError;}
  746. #if 1
  747. {
  748. jeVFile * HFile;
  749. HFile = jeVFile_GetHintsFile(SubFile);
  750. if (jeActor_DefWriteHeader(Ad,HFile)==JE_FALSE)
  751. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteToFile - Failed to write hints"); goto WriteError;}
  752. }
  753. #else
  754. if (jeActor_DefWriteHeader(Ad,SubFile)==JE_FALSE)
  755. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteToFile - Failed to write header"); goto WriteError;}
  756. #endif
  757. if (jeVFile_Close(SubFile)==JE_FALSE)
  758. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE , "jeActor_DefWriteToFile - Failed to close header"); goto WriteError;}
  759. if (Ad->Body != NULL)
  760. {
  761. SubFile = jeVFile_Open(VFile,JE_ACTOR_BODY_NAME,JE_VFILE_OPEN_CREATE);
  762. if (SubFile == NULL)
  763. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteToFile - Failed to open body subfile"); goto WriteError;}
  764. if (jeBody_WriteToFile(Ad->Body,SubFile)==JE_FALSE)
  765. { jeErrorLog_Add( JE_ERR_SUBSYSTEM_FAILURE , "jeActor_DefWriteToFile - Failed to write body"); goto WriteError;}
  766. if (jeVFile_Close(SubFile)==JE_FALSE)
  767. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE , "jeActor_DefWriteToFile - Failed to close body subfile"); goto WriteError;}
  768. }
  769. MotionDirectory = jeVFile_Open(VFile,JE_MOTION_DIRECTORY_NAME,
  770. JE_VFILE_OPEN_DIRECTORY | JE_VFILE_OPEN_CREATE);
  771. if (MotionDirectory == NULL)
  772. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefWriteToFile - Failed to open motion subdirectory"); goto WriteError;}
  773. // <> CB note : could save some by combining these motions in one LZ file
  774. for (i=0; i<Ad->MotionCount; i++)
  775. {
  776. char FName[1000];
  777. sprintf(FName,"%d",i);
  778. SubFile = jeVFile_Open(MotionDirectory,FName,JE_VFILE_OPEN_CREATE);
  779. if (SubFile == NULL)
  780. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefWriteToFile - Failed to open motion subfile"); goto WriteError;}
  781. #if 0 //{
  782. if (jeMotion_WriteToFile(Ad->MotionArray[i],SubFile)==JE_FALSE)
  783. { jeErrorLog_AddString( JE_ERR_SUBSYSTEM_FAILURE , "jeActor_DefWriteToFile - Failed to write motion"); goto WriteError;}
  784. #else //}{
  785. {
  786. jeVFile * LZFS;
  787. LZFS = jeVFile_OpenNewSystem(SubFile,JE_VFILE_TYPE_LZ, NULL, NULL, JE_VFILE_OPEN_CREATE);
  788. if ( ! LZFS )
  789. { jeErrorLog_Add( JE_ERR_FILEIO_OPEN , "jeActor_DefWriteToFile - Failed to open compressed system"); goto WriteError;}
  790. if (jeMotion_WriteToFile(Ad->MotionArray[i],LZFS)==JE_FALSE)
  791. { jeErrorLog_Add( JE_ERR_SUBSYSTEM_FAILURE , "jeActor_DefWriteToFile - Failed to write motion"); goto WriteError;}
  792. if ( ! jeVFile_Close(LZFS) )
  793. { jeErrorLog_Add( JE_ERR_FILEIO_CLOSE , "jeActor_DefWriteToFile - Failed to close compressed system"); goto WriteError;}
  794. }
  795. #endif //}
  796. if (jeVFile_Close(SubFile)==JE_FALSE)
  797. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteToFile - Failed to close motion subfile"); goto WriteError;}
  798. }
  799. if (jeVFile_Close(MotionDirectory)==JE_FALSE)
  800. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteToFile - Failed to close motion subdirectory"); goto WriteError;}
  801. if (jeVFile_Close(VFile)==JE_FALSE)
  802. { jeErrorLog_Add( JE_ERR_FILEIO_WRITE , "jeActor_DefWriteToFile - Failed to close actor subsystem"); goto WriteError;}
  803. return JE_TRUE;
  804. WriteError:
  805. return JE_FALSE;
  806. }
  807. JETAPI jeBoolean JETCC jeActor_GetBoneTransform(const jeActor *A, const char *BoneName, jeXForm3d *Transform)
  808. {
  809. int BoneIndex;
  810. assert( jeActor_IsValid(A)!=JE_FALSE );
  811. assert( Transform!= NULL );
  812. if (jeActor_GetBoneIndex(A,BoneName,&BoneIndex)==JE_FALSE)
  813. {
  814. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_GetBoneTransform: Named bone not found", BoneName);
  815. return JE_FALSE;
  816. }
  817. jePose_GetJointTransform( A->Pose, BoneIndex, Transform);
  818. assert ( jeXForm3d_IsOrthonormal(Transform) != JE_FALSE );
  819. return JE_TRUE;
  820. }
  821. static void JETCF jeActor_AccumulateMinMax(
  822. jeVec3d *P,jeVec3d *Mins,jeVec3d *Maxs)
  823. {
  824. assert( jeVec3d_IsValid( P ) != JE_FALSE );
  825. assert( jeVec3d_IsValid(Mins) != JE_FALSE );
  826. assert( jeVec3d_IsValid(Maxs) != JE_FALSE );
  827. if (P->X < Mins->X) Mins->X = P->X;
  828. if (P->Y < Mins->Y) Mins->Y = P->Y;
  829. if (P->Z < Mins->Z) Mins->Z = P->Z;
  830. if (P->X > Maxs->X) Maxs->X = P->X;
  831. if (P->Y > Maxs->Y) Maxs->Y = P->Y;
  832. if (P->Z > Maxs->Z) Maxs->Z = P->Z;
  833. }
  834. static jeBoolean JETCF jeActor_GetBoneBoundingBoxByIndex(
  835. const jeActor *A,
  836. int BoneIndex,
  837. jeVec3d *Corner,
  838. jeVec3d *DX,
  839. jeVec3d *DY,
  840. jeVec3d *DZ)
  841. {
  842. jeVec3d Min,Max;
  843. jeVec3d Orientation;
  844. jeXForm3d Transform;
  845. assert( jeActor_IsValid(A) != JE_FALSE );
  846. assert( jeActor_DefIsValid(A->ActorDefinition) != JE_FALSE );
  847. assert( A->ActorDefinition->Body != NULL );
  848. assert( Corner );
  849. assert( DX );
  850. assert( DY );
  851. assert( DZ );
  852. assert( (BoneIndex < jePose_GetJointCount(A->Pose)) || (BoneIndex ==JE_POSE_ROOT_JOINT));
  853. assert( (BoneIndex >=0) || (BoneIndex ==JE_POSE_ROOT_JOINT));
  854. if (jeBody_GetBoundingBox( A->ActorDefinition->Body, BoneIndex, &Min, &Max )==JE_FALSE)
  855. {
  856. // not probably a real error. It's possible that the bone has no geometry, so it
  857. // has no bounding box.
  858. return JE_FALSE;
  859. }
  860. // scale bounding box:
  861. {
  862. jeVec3d Scale;
  863. jePose_GetScale(A->Pose, &Scale);
  864. assert( jeVec3d_IsValid(&Scale) != JE_FALSE );
  865. Min.X *= Scale.X;
  866. Min.Y *= Scale.Y;
  867. Min.Z *= Scale.Z;
  868. Max.X *= Scale.X;
  869. Max.Y *= Scale.Y;
  870. Max.Z *= Scale.Z;
  871. }
  872. jePose_GetJointTransform(A->Pose,BoneIndex,&(Transform));
  873. jeVec3d_Subtract(&Max,&Min,&Orientation);
  874. DX->X = Orientation.X; DX->Y = DX->Z = 0.0f;
  875. DY->Y = Orientation.Y; DY->X = DY->Z = 0.0f;
  876. DZ->Z = Orientation.Z; DZ->X = DZ->Y = 0.0f;
  877. // transform into world space
  878. jeXForm3d_Transform(&(Transform),&Min,&Min);
  879. jeXForm3d_Rotate(&(Transform),DX,DX);
  880. jeXForm3d_Rotate(&(Transform),DY,DY);
  881. jeXForm3d_Rotate(&(Transform),DZ,DZ);
  882. *Corner = Min;
  883. return JE_TRUE;
  884. }
  885. static jeBoolean JETCF jeActor_GetBoneExtBoxByIndex(
  886. const jeActor *A,
  887. int BoneIndex,
  888. jeExtBox *ExtBox)
  889. {
  890. jeVec3d Min;
  891. jeVec3d DX,DY,DZ,Corner;
  892. assert( ExtBox );
  893. if (jeActor_GetBoneBoundingBoxByIndex(A,BoneIndex,&Min,&DX,&DY,&DZ)==JE_FALSE)
  894. {
  895. // Commented out by Incarnadine: This happens frequently when dealing
  896. // with boned objects if a bone has no geometry (like any physiqued object
  897. // with BIP01). It was slowing things down to make this call several times / tick.
  898. //jeErrorLog_Add(JE_ERR_BAD_PARAMETER,"jeActor_GetBoneExtBoxByIndex - ");
  899. return JE_FALSE;
  900. }
  901. ExtBox->Min = Min;
  902. ExtBox->Max = Min;
  903. Corner = Min;
  904. // should use extent box (extbox) methods rather than this
  905. jeVec3d_Add(&Corner,&DX,&Corner);
  906. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  907. jeVec3d_Add(&Corner,&DZ,&Corner);
  908. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  909. jeVec3d_Subtract(&Corner,&DX,&Corner);
  910. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  911. jeVec3d_Add(&Corner,&DY,&Corner);
  912. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  913. jeVec3d_Add(&Corner,&DX,&Corner);
  914. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  915. jeVec3d_Subtract(&Corner,&DZ,&Corner);
  916. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  917. jeVec3d_Subtract(&Corner,&DX,&Corner);
  918. jeActor_AccumulateMinMax(&Corner,&(ExtBox->Min),&(ExtBox->Max));
  919. return JE_TRUE;
  920. }
  921. JETAPI jeBoolean JETCC jeActor_GetBoneExtBox(const jeActor *A,
  922. const char *BoneName,
  923. jeExtBox *ExtBox)
  924. {
  925. int BoneIndex;
  926. assert( jeActor_IsValid(A) != JE_FALSE);
  927. assert( ExtBox != NULL );
  928. if (jeActor_GetBoneIndex(A,BoneName,&BoneIndex)==JE_FALSE)
  929. {
  930. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_GetBoneExtBox: Named bone for bounding box not found: ", BoneName);
  931. return JE_FALSE;
  932. }
  933. return jeActor_GetBoneExtBoxByIndex(A,BoneIndex,ExtBox);
  934. }
  935. JETAPI jeBoolean JETCC jeActor_GetBoneBoundingBox(const jeActor *A,
  936. const char *BoneName,
  937. jeVec3d *Corner,
  938. jeVec3d *DX,
  939. jeVec3d *DY,
  940. jeVec3d *DZ)
  941. {
  942. int BoneIndex;
  943. assert( jeActor_IsValid(A) != JE_FALSE);
  944. assert( Corner != NULL );
  945. assert( DX != NULL );
  946. assert( DY != NULL );
  947. assert( DZ != NULL );
  948. if (jeActor_GetBoneIndex(A,BoneName,&BoneIndex)==JE_FALSE)
  949. {
  950. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_GetBoneBoundingBox - Named bone for bounding box not found: ", BoneName);
  951. return JE_FALSE;
  952. }
  953. if (jeActor_GetBoneBoundingBoxByIndex(A,BoneIndex,Corner,DX,DY,DZ)==JE_FALSE)
  954. {
  955. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_GetBoneBoundingBox - Failed to get bounding box named: ", BoneName);
  956. //jeErrorLog_AppendString(BoneName);
  957. return JE_FALSE;
  958. }
  959. return JE_TRUE;
  960. }
  961. JETAPI jeBoolean JETCC jeActor_GetExtBox(const jeActor *A, jeExtBox *ExtBox)
  962. {
  963. jeXForm3d Transform;
  964. assert( jeActor_IsValid(A) != JE_FALSE);
  965. assert( ExtBox != NULL );
  966. jePose_GetJointTransform( A->Pose,
  967. A->BoundingBoxCenterBoneIndex,
  968. &Transform);
  969. assert ( jeXForm3d_IsOrthonormal(&Transform) != JE_FALSE );
  970. jeVec3d_Add( &(Transform.Translation), &(A->CollisionExtBox.Min), &(ExtBox->Min));
  971. jeVec3d_Add( &(Transform.Translation), &(A->CollisionExtBox.Max), &(ExtBox->Max));
  972. return JE_TRUE;
  973. }
  974. JETAPI jeBoolean JETCC jeActor_SetExtBox(jeActor *A,
  975. const jeExtBox *ExtBox,
  976. const char *CenterOnThisNamedBone)
  977. {
  978. assert( jeActor_IsValid(A) != JE_FALSE);
  979. assert( jeExtBox_IsValid(ExtBox) != JE_FALSE);
  980. A->CollisionExtBox.Min = ExtBox->Min;
  981. A->CollisionExtBox.Max = ExtBox->Max;
  982. if (jeActor_GetBoneIndex(A,CenterOnThisNamedBone,&(A->BoundingBoxCenterBoneIndex))==JE_FALSE)
  983. {
  984. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_SetExtBox: Named bone for bounding box not found ", CenterOnThisNamedBone);
  985. return JE_FALSE;
  986. }
  987. return JE_TRUE;
  988. }
  989. // Gets the rendering hint bounding box from the actor
  990. JETAPI jeBoolean JETCC jeActor_GetRenderHintExtBox(const jeActor *A, jeExtBox *Box, jeBoolean *Enabled)
  991. {
  992. jeXForm3d Transform;
  993. assert( jeActor_IsValid(A) != JE_FALSE);
  994. assert( Box != NULL );
  995. assert( Enabled != NULL );
  996. jePose_GetJointTransform( A->Pose,
  997. A->RenderHintExtBoxCenterBoneIndex,
  998. &Transform);
  999. assert ( jeXForm3d_IsOrthonormal(&Transform) != JE_FALSE );
  1000. *Box = A->RenderHintExtBox;
  1001. jeExtBox_Translate ( Box, Transform.Translation.X,
  1002. Transform.Translation.Y,
  1003. Transform.Translation.Z );
  1004. *Enabled = A->RenderHintExtBoxEnabled;
  1005. return JE_TRUE;
  1006. }
  1007. // Sets a rendering hint bounding box from the actor
  1008. JETAPI jeBoolean JETCC jeActor_SetRenderHintExtBox(jeActor *A, const jeExtBox *Box,
  1009. const char *CenterOnThisNamedBone)
  1010. {
  1011. assert( jeActor_IsValid(A) != JE_FALSE);
  1012. assert( Box != NULL );
  1013. assert( Box->Max.X >= Box->Min.X );
  1014. assert( Box->Max.Y >= Box->Min.Y );
  1015. assert( Box->Max.Z >= Box->Min.Z );
  1016. if (jeActor_GetBoneIndex(A,CenterOnThisNamedBone,&(A->RenderHintExtBoxCenterBoneIndex))==JE_FALSE)
  1017. {
  1018. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_SetRenderHintExtBox: Named bone for render hint box not found: ", CenterOnThisNamedBone);
  1019. return JE_FALSE;
  1020. }
  1021. A->RenderHintExtBox = *Box;
  1022. if ( (Box->Min.X == 0.0f) && (Box->Max.X == 0.0f)
  1023. && (Box->Min.Y == 0.0f) && (Box->Max.Y == 0.0f)
  1024. && (Box->Min.Z == 0.0f) && (Box->Max.Z == 0.0f) )
  1025. {
  1026. A->RenderHintExtBoxEnabled = JE_FALSE;
  1027. }
  1028. else
  1029. {
  1030. A->RenderHintExtBoxEnabled = JE_TRUE;
  1031. }
  1032. return JE_TRUE;
  1033. }
  1034. JETAPI void *JETCC jeActor_GetUserData(const jeActor *A)
  1035. {
  1036. assert( jeActor_IsValid(A) != JE_FALSE);
  1037. return A->UserData;
  1038. }
  1039. JETAPI void JETCC jeActor_SetUserData(jeActor *A, void *UserData)
  1040. {
  1041. assert( jeActor_IsValid(A) != JE_FALSE);
  1042. A->UserData = UserData;
  1043. }
  1044. #define MAX(aa,bb) ( (aa)>(bb)?(aa):(bb) )
  1045. #define MIN(aa,bb) ( (aa)<(bb)?(aa):(bb) )
  1046. static void JETCF jeActor_StretchBoundingBox( jeVec3d *Min, jeVec3d *Max,
  1047. const jeVec3d *Corner,
  1048. const jeVec3d *DX, const jeVec3d *DY, const jeVec3d *DZ)
  1049. {
  1050. jeVec3d P;
  1051. P = *Corner;
  1052. Min->X = MIN(Min->X,P.X), Min->Y = MIN(Min->Y,P.Y), Min->Z = MIN(Min->Z,P.Z);
  1053. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1054. jeVec3d_Add (Corner ,DX,&P);
  1055. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1056. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1057. jeVec3d_Add (&P, DZ,&P);
  1058. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1059. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1060. jeVec3d_Subtract(&P,DX,&P);
  1061. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1062. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1063. jeVec3d_Add (&P,DY,&P);
  1064. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1065. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1066. jeVec3d_Add (&P,DX,&P);
  1067. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1068. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1069. jeVec3d_Subtract(&P,DZ,&P);
  1070. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1071. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1072. jeVec3d_Subtract(&P,DX,&P);
  1073. Min->X = MIN(Min->X,P.X); Min->Y = MIN(Min->Y,P.Y); Min->Z = MIN(Min->Z,P.Z);
  1074. Max->X = MAX(Max->X,P.X); Max->Y = MAX(Max->Y,P.Y); Max->Z = MAX(Max->Z,P.Z);
  1075. }
  1076. JETAPI jeBoolean JETCC jeActor_GetDynamicExtBox( const jeActor *A, jeExtBox *ExtBox)
  1077. {
  1078. #define JE_ACTOR_REALLY_BIG_NUMBER (9e9f)
  1079. jeVec3d Corner;
  1080. jeVec3d DX;
  1081. jeVec3d DY;
  1082. jeVec3d DZ;
  1083. int Count,i,BCount;
  1084. assert( jeActor_IsValid(A) != JE_FALSE);
  1085. assert( A->ActorDefinition->Body != NULL );
  1086. jeVec3d_Set(&(ExtBox->Min),
  1087. JE_ACTOR_REALLY_BIG_NUMBER,JE_ACTOR_REALLY_BIG_NUMBER,JE_ACTOR_REALLY_BIG_NUMBER);
  1088. jeVec3d_Set(&(ExtBox->Max),
  1089. -JE_ACTOR_REALLY_BIG_NUMBER,-JE_ACTOR_REALLY_BIG_NUMBER,-JE_ACTOR_REALLY_BIG_NUMBER);
  1090. BCount = 0;
  1091. Count = jeBody_GetBoneCount( A->ActorDefinition->Body );
  1092. for (i=0; i< Count; i++)
  1093. {
  1094. if (jeActor_GetBoneBoundingBoxByIndex(A,i,&Corner,&DX,&DY,&DZ)!=JE_FALSE)
  1095. {
  1096. jeActor_StretchBoundingBox( &(ExtBox->Min),
  1097. &(ExtBox->Max),&Corner,&DX,&DY,&DZ);
  1098. BCount ++;
  1099. }
  1100. }
  1101. if (BCount>0)
  1102. {
  1103. return JE_TRUE;
  1104. }
  1105. return JE_FALSE;
  1106. }
  1107. JETAPI jeBoolean JETCC jeActor_Attach( jeActor *Slave, const char *SlaveBoneName,
  1108. const jeActor *Master, const char *MasterBoneName,
  1109. const jeXForm3d *Attachment)
  1110. {
  1111. int SlaveBoneIndex,MasterBoneIndex;
  1112. assert( jeActor_IsValid(Slave) != JE_FALSE);
  1113. assert( jeActor_IsValid(Master) != JE_FALSE);
  1114. assert( jeXForm3d_IsOrthonormal(Attachment) != JE_FALSE );
  1115. assert( MasterBoneName != NULL ); // might this be possible?
  1116. if (jeActor_GetBoneIndex(Slave,SlaveBoneName,&(SlaveBoneIndex))==JE_FALSE)
  1117. {
  1118. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_Attach: Named bone for slave not found: ", SlaveBoneName);
  1119. return JE_FALSE;
  1120. }
  1121. if (jeActor_GetBoneIndex(Master,MasterBoneName,&(MasterBoneIndex))==JE_FALSE)
  1122. {
  1123. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"Named bone for master not found: ", MasterBoneName);
  1124. return JE_FALSE;
  1125. }
  1126. return jePose_Attach( Slave->Pose, SlaveBoneIndex,
  1127. Master->Pose, MasterBoneIndex,
  1128. Attachment);
  1129. }
  1130. JETAPI void JETCC jeActor_Detach(jeActor *A)
  1131. {
  1132. assert( jeActor_IsValid(A) != JE_FALSE);
  1133. jePose_Detach( A->Pose );
  1134. }
  1135. JETAPI jeBoolean JETCC jeActor_GetBoneAttachment(const jeActor *A,
  1136. const char *BoneName,
  1137. jeXForm3d *Attachment)
  1138. {
  1139. int BoneIndex;
  1140. assert( jeActor_IsValid(A) != JE_FALSE);
  1141. assert( Attachment != NULL );
  1142. if (jeActor_GetBoneIndex(A,BoneName,&(BoneIndex))==JE_FALSE)
  1143. {
  1144. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_GetBoneAttachment: Named bone not found: ", BoneName);
  1145. return JE_FALSE;
  1146. }
  1147. jePose_GetJointAttachment(A->Pose,BoneIndex, Attachment);
  1148. assert ( jeXForm3d_IsOrthonormal(Attachment) != JE_FALSE );
  1149. return JE_TRUE;
  1150. }
  1151. JETAPI jeBoolean JETCC jeActor_SetBoneAttachment(jeActor *A,
  1152. const char *BoneName,
  1153. jeXForm3d *Attachment)
  1154. {
  1155. int BoneIndex;
  1156. assert( jeActor_IsValid(A) != JE_FALSE);
  1157. assert( jeXForm3d_IsOrthonormal(Attachment) != JE_FALSE );
  1158. if (jeActor_GetBoneIndex(A,BoneName,&(BoneIndex))==JE_FALSE)
  1159. {
  1160. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_SetBoneAttachment: Named bone not found: ", BoneName);
  1161. return JE_FALSE;
  1162. }
  1163. jePose_SetJointAttachment(A->Pose,BoneIndex, Attachment);
  1164. return JE_TRUE;
  1165. }
  1166. //-------------------------------------------------------------------------------------------------
  1167. // Actor Cuing system
  1168. //-------------------------------------------------------------------------------------------------
  1169. #define ACTOR_CUE_MINIMUM_BLEND (0.0001f)
  1170. #define ACTOR_CUE_MAXIMUM_BLEND (0.999f)
  1171. static jeBoolean JETCF jeActor_IsAnimationCueDead(jeActor *A, int Index)
  1172. {
  1173. jeBoolean Kill= JE_FALSE;
  1174. jeFloat BlendAmount;
  1175. jeMotion *M;
  1176. assert( jeActor_IsValid(A) != JE_FALSE);
  1177. assert( (Index>=0) && (Index<jeMotion_GetSubMotionCount(A->CueMotion)));
  1178. M = A->CueMotion;
  1179. BlendAmount = jeMotion_GetBlendAmount(M,Index,0.0f);
  1180. if (BlendAmount <= ACTOR_CUE_MINIMUM_BLEND)
  1181. {
  1182. int KeyCount;
  1183. jePath *P;
  1184. jeFloat KeyTime;
  1185. P = jeMotion_GetBlendPath(M,Index);
  1186. assert( P != NULL );
  1187. KeyCount = jePath_GetKeyframeCount(P,JE_PATH_TRANSLATION_CHANNEL);
  1188. if (KeyCount>0)
  1189. {
  1190. jeXForm3d Dummy;
  1191. jeFloat TimeOffset = -jeMotion_GetTimeOffset( M, Index);
  1192. jePath_GetKeyframe( P, KeyCount-1, JE_PATH_TRANSLATION_CHANNEL, &KeyTime, &Dummy );
  1193. if ( KeyTime <= TimeOffset )
  1194. {
  1195. Kill = JE_TRUE;
  1196. }
  1197. }
  1198. else
  1199. {
  1200. Kill = JE_TRUE;
  1201. }
  1202. }
  1203. return Kill;
  1204. }
  1205. static void JETCF jeActor_KillCue( jeActor *A, int Index )
  1206. {
  1207. jeMotion *M;
  1208. assert( jeActor_IsValid(A) != JE_FALSE);
  1209. assert( (Index>=0) && (Index<jeMotion_GetSubMotionCount(A->CueMotion)));
  1210. M = jeMotion_RemoveSubMotion(A->CueMotion,Index);
  1211. }
  1212. JETAPI jeBoolean JETCC jeActor_AnimationNudge(jeActor *A, jeXForm3d *Offset)
  1213. {
  1214. jeMotion *M;
  1215. int i,Count;
  1216. assert( jeActor_IsValid(A) != JE_FALSE);
  1217. assert( jeXForm3d_IsOrthonormal(Offset) != JE_FALSE );
  1218. M = A->CueMotion;
  1219. Count = jeMotion_GetSubMotionCount(M);
  1220. for (i=Count-1; i>=0; i--)
  1221. {
  1222. jeXForm3d Transform;
  1223. const jeXForm3d *pTransform;
  1224. pTransform = jeMotion_GetBaseTransform( M, i );
  1225. if ( pTransform != NULL )
  1226. {
  1227. Transform = *pTransform;
  1228. jeXForm3d_Multiply(Offset,&Transform,&Transform);
  1229. jeXForm3d_Orthonormalize(&Transform);
  1230. jeMotion_SetBaseTransform( M, i, &Transform);
  1231. }
  1232. }
  1233. return JE_TRUE;
  1234. }
  1235. JETAPI jeBoolean JETCC jeActor_AnimationRemoveLastCue( jeActor *A )
  1236. {
  1237. int Count;
  1238. assert( jeActor_IsValid(A) != JE_FALSE);
  1239. Count = jeMotion_GetSubMotionCount(A->CueMotion);
  1240. if (Count>0)
  1241. {
  1242. jeActor_KillCue( A, Count-1 );
  1243. return JE_TRUE;
  1244. }
  1245. return JE_FALSE;
  1246. }
  1247. JETAPI jeBoolean JETCC jeActor_AnimationCue( jeActor *A,
  1248. jeMotion *Motion,
  1249. jeFloat TimeScaleFactor,
  1250. jeFloat TimeIntoMotion,
  1251. jeFloat BlendTime,
  1252. jeFloat BlendFromAmount,
  1253. jeFloat BlendToAmount,
  1254. const jeXForm3d *MotionTransform)
  1255. {
  1256. int Index;
  1257. assert( jeActor_IsValid(A) != JE_FALSE);
  1258. assert( (BlendFromAmount>=0.0f) && (BlendFromAmount<=1.0f));
  1259. assert( ( BlendToAmount>=0.0f) && ( BlendToAmount<=1.0f));
  1260. assert( (MotionTransform==NULL) || (jeXForm3d_IsOrthonormal(MotionTransform)) != JE_FALSE );
  1261. assert( Motion != NULL );
  1262. assert( BlendTime >= 0.0f);
  1263. if (BlendTime==0.0f)
  1264. {
  1265. BlendFromAmount = BlendToAmount;
  1266. BlendTime = 1.0f; // anything that is > JE_TKA_TIME_TOLERANCE
  1267. }
  1268. if (jeMotion_AddSubMotion( A->CueMotion, TimeScaleFactor, -TimeIntoMotion, Motion,
  1269. TimeIntoMotion, BlendFromAmount,
  1270. TimeIntoMotion + BlendTime, BlendToAmount,
  1271. MotionTransform, &Index )==JE_FALSE)
  1272. {
  1273. return JE_FALSE;
  1274. }
  1275. return JE_TRUE;
  1276. }
  1277. JETAPI jeBoolean JETCC jeActor_AnimationStep(jeActor *A, jeFloat DeltaTime )
  1278. {
  1279. int i,Coverage,Count;
  1280. jeMotion *M;
  1281. jeMotion *SubM;
  1282. assert( jeActor_IsValid(A) != JE_FALSE);
  1283. assert( DeltaTime >= 0.0f );
  1284. jePose_ClearCoverage(A->Pose,0);
  1285. M = A->CueMotion;
  1286. Count = jeMotion_GetSubMotionCount(M);
  1287. for (i=Count-1; i>=0; i--)
  1288. {
  1289. jeFloat TimeOffset = jeMotion_GetTimeOffset( M, i );
  1290. TimeOffset = TimeOffset - DeltaTime;
  1291. jeMotion_SetTimeOffset( M, i, TimeOffset);
  1292. if (jeActor_IsAnimationCueDead(A,i))
  1293. {
  1294. jeActor_KillCue(A,i);
  1295. }
  1296. else
  1297. {
  1298. jeBoolean SetWithBlending= JE_TRUE;
  1299. jeFloat BlendAmount;
  1300. SubM = jeMotion_GetSubMotion(M,i);
  1301. assert( SubM != NULL );
  1302. BlendAmount = jeMotion_GetBlendAmount( M,i,0.0f );
  1303. if (BlendAmount >= ACTOR_CUE_MAXIMUM_BLEND)
  1304. {
  1305. SetWithBlending = JE_FALSE;
  1306. }
  1307. Coverage = jePose_AccumulateCoverage(A->Pose,SubM, SetWithBlending);
  1308. if ( Coverage == 0 )
  1309. {
  1310. jeActor_KillCue(A,i);
  1311. }
  1312. }
  1313. }
  1314. jePose_SetMotion( A->Pose, M, 0.0f, NULL );
  1315. jeMotion_SetupEventIterator(M,-DeltaTime,0.0f);
  1316. return JE_TRUE;
  1317. }
  1318. JETAPI jeBoolean JETCC jeActor_AnimationStepBoneOptimized(jeActor *A, jeFloat DeltaTime, const char *BoneName )
  1319. {
  1320. int i,Coverage,Count;
  1321. jeMotion *M;
  1322. jeMotion *SubM;
  1323. assert( jeActor_IsValid(A) != JE_FALSE);
  1324. assert( DeltaTime >= 0.0f );
  1325. if (BoneName == NULL)
  1326. {
  1327. A->StepBoneIndex = JE_POSE_ROOT_JOINT;
  1328. }
  1329. else
  1330. {
  1331. jeBoolean LookupBoneName= JE_TRUE;
  1332. const char *LastBoneName;
  1333. jeXForm3d Attachment;
  1334. int LastParentBoneIndex;
  1335. if (A->StepBoneIndex >= 0)
  1336. {
  1337. jeBody_GetBone( A->ActorDefinition->Body,A->StepBoneIndex,&LastBoneName,&Attachment,&LastParentBoneIndex);
  1338. if ( (LastBoneName != NULL) )
  1339. if (_stricmp(LastBoneName,BoneName)==0) // Case insensitive compare -- Incarnadine
  1340. LookupBoneName = JE_FALSE;
  1341. }
  1342. if (LookupBoneName != JE_FALSE)
  1343. {
  1344. if (jeActor_GetBoneIndex(A,BoneName,&(A->StepBoneIndex))==JE_FALSE)
  1345. {
  1346. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_AnimationStepBoneOptimized: Named bone not found: ", BoneName);
  1347. return JE_FALSE;
  1348. }
  1349. }
  1350. }
  1351. jePose_ClearCoverage(A->Pose,0);
  1352. M = A->CueMotion;
  1353. Count = jeMotion_GetSubMotionCount(M);
  1354. for (i=Count-1; i>=0; i--)
  1355. {
  1356. jeFloat TimeOffset = jeMotion_GetTimeOffset( M, i );
  1357. TimeOffset = TimeOffset - DeltaTime;
  1358. jeMotion_SetTimeOffset( M, i, TimeOffset);
  1359. if (jeActor_IsAnimationCueDead(A,i))
  1360. {
  1361. jeActor_KillCue(A,i);
  1362. }
  1363. else
  1364. {
  1365. jeBoolean SetWithBlending= JE_TRUE;
  1366. jeFloat BlendAmount;
  1367. SubM = jeMotion_GetSubMotion(M,i);
  1368. assert( SubM != NULL );
  1369. BlendAmount = jeMotion_GetBlendAmount( M,i,0.0f );
  1370. if (BlendAmount >= ACTOR_CUE_MAXIMUM_BLEND)
  1371. {
  1372. SetWithBlending = JE_FALSE;
  1373. }
  1374. Coverage = jePose_AccumulateCoverage(A->Pose,SubM, SetWithBlending);
  1375. if ( Coverage == 0 )
  1376. {
  1377. jeActor_KillCue(A,i);
  1378. }
  1379. }
  1380. }
  1381. jePose_SetMotionForABone( A->Pose, M, 0.0f, NULL, A->StepBoneIndex );
  1382. jeMotion_SetupEventIterator(M,-DeltaTime,0.0f);
  1383. return JE_TRUE;
  1384. }
  1385. JETAPI jeBoolean JETCC jeActor_AnimationTestStep(jeActor *A, jeFloat DeltaTime)
  1386. {
  1387. assert( jeActor_IsValid(A) != JE_FALSE);
  1388. assert( DeltaTime >= 0.0f );
  1389. jePose_SetMotion( A->Pose, A->CueMotion , DeltaTime, NULL );
  1390. return JE_TRUE;
  1391. }
  1392. JETAPI jeBoolean JETCC jeActor_AnimationTestStepBoneOptimized(jeActor *A, jeFloat DeltaTime, const char *BoneName)
  1393. {
  1394. assert( jeActor_IsValid(A) != JE_FALSE);
  1395. assert( DeltaTime >= 0.0f );
  1396. if (BoneName == NULL)
  1397. {
  1398. A->StepBoneIndex = JE_POSE_ROOT_JOINT;
  1399. }
  1400. else
  1401. {
  1402. jeBoolean LookupBoneName= JE_TRUE;
  1403. const char *LastBoneName;
  1404. jeXForm3d Attachment;
  1405. int LastParentBoneIndex;
  1406. if (A->StepBoneIndex >= 0)
  1407. {
  1408. jeBody_GetBone( A->ActorDefinition->Body,A->StepBoneIndex,&LastBoneName,&Attachment,&LastParentBoneIndex);
  1409. if ( (LastBoneName != NULL) )
  1410. if (_stricmp(LastBoneName,BoneName)==0) // Case insensitive compare -- Incarnadine
  1411. LookupBoneName = JE_FALSE;
  1412. }
  1413. if (LookupBoneName != JE_FALSE)
  1414. {
  1415. if (jeActor_GetBoneIndex(A,BoneName,&(A->StepBoneIndex))==JE_FALSE)
  1416. {
  1417. jeErrorLog_AddString(JE_ERR_SUBSYSTEM_FAILURE,"jeActor_AnimationTestStepBoneOptimized: Named bone not found:", BoneName);
  1418. return JE_FALSE;
  1419. }
  1420. }
  1421. }
  1422. jePose_SetMotionForABone( A->Pose, A->CueMotion , DeltaTime, NULL,A->StepBoneIndex );
  1423. return JE_TRUE;
  1424. }
  1425. JETAPI jeBoolean JETCC jeActor_GetAnimationEvent(
  1426. jeActor *A,
  1427. const char **ppEventString) // Return data, if found
  1428. // returns the event string for the 'next' event that occured during the last
  1429. // animation step time delta.
  1430. // if the return value is JE_FALSE, there are no more events, and ppEventString will be Empty
  1431. {
  1432. jeFloat Time;
  1433. assert( jeActor_IsValid(A) != JE_FALSE);
  1434. return jeMotion_GetNextEvent(A->CueMotion, &Time, ppEventString );
  1435. }
  1436. JETAPI jeBoo