/branches/jet3d_dev_msvc2005/source/Objects/PathObject/PathObj.cpp

# · C++ · 2354 lines · 1728 code · 495 blank · 131 comment · 300 complexity · 73c7958278df1dc6396ea562dad2138b MD5 · raw file

Large files are truncated click here to view the full file

  1. /****************************************************************************************/
  2. /* PATHOBJ.C */
  3. /* */
  4. /* Author: */
  5. /* Description: */
  6. /* */
  7. /* The contents of this file are subject to the Jet3D Public License */
  8. /* Version 1.02 (the "License"); you may not use this file except in */
  9. /* compliance with the License. You may obtain a copy of the License at */
  10. /* http://www.jet3d.com */
  11. /* */
  12. /* Software distributed under the License is distributed on an "AS IS" */
  13. /* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
  14. /* the License for the specific language governing rights and limitations */
  15. /* under the License. */
  16. /* */
  17. /* The Original Code is Jet3D, released December 12, 1999. */
  18. /* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */
  19. /* */
  20. /****************************************************************************************/
  21. //#include "forcelib.h"
  22. #ifdef WIN32
  23. #include <windows.h>
  24. #endif
  25. #include <memory.h>
  26. #include <assert.h>
  27. #include <math.h>
  28. #include <stdlib.h>
  29. #ifdef BUILD_BE
  30. #include <image.h>
  31. #include <sys/param.h>
  32. #define min(a,b) (((a)<(b))?(a):(b))
  33. #define max(a,b) (((a)>(b))?(a):(b))
  34. #define stricmp strcasecmp
  35. #endif
  36. #include <string.h>
  37. #include <float.h>
  38. #include <limits.h>
  39. #include "Errorlog.h"
  40. #include "PathObj.h"
  41. #include "jeTypes.h"
  42. #include "jeProperty.h"
  43. #include "Jet.h"
  44. #include "Ram.h"
  45. #include "Channel.h"
  46. #include "Trigger.h"
  47. #include "ObjectMsg.h"
  48. ////////////////////// IMPORTANT
  49. // If you change the structure formats, data ids, then bump the MAJOR version number
  50. // Minor version number changes will not change the format
  51. //////////////////////
  52. #define PATHOBJ_VERSION 1
  53. typedef struct PathObj PathObj;
  54. #ifdef WIN32
  55. static HINSTANCE hInstance;
  56. #endif
  57. #ifdef BUILD_BE
  58. static image_id hInstance;
  59. #endif
  60. static jeObject * PathObject_FindObjectFromName(jeWorld *World, char *NameToFind);
  61. static jeBoolean PathObject_GetPropertyDataIdFromName(jeWorld *World, jeObject *Obj, char *NameToFind, int32 *PropDataId);
  62. static jeBoolean PathObject_BuildObjectNameList(PathObj *pPathObj, int TimeLineNdx, int32 *NameCount);
  63. static jeBoolean PathObject_BuildPropertyNameList(PathObj *pPathObj, int TimeLineNdx, int32 *NameCount);
  64. static jeBoolean PathObject_GetPropertyInfoFromDataId(jeWorld *World, jeObject *Obj, int32 DataId, int32 *Type, jeProperty_Data *Data);
  65. static jeBoolean PathObject_PutDataIntoChannelObject(PathObj *pPathObj, int TimeLineNdx, jeXForm3d *XF);
  66. static jeBoolean PathObject_SampleMotion(PathObj *pPathObj, int TimeLineNdx);
  67. static jeBoolean PathObject_ProcessEvents(PathObj *pPathObj, int TimeLineNdx, float StartTime, float EndTime);
  68. static jeBoolean PathObject_ValidateObject(PathObj *pPathObj, int ChannelType, jeObject *Obj, int PropID);
  69. static jeBoolean PathObject_BuildAllMotions(PathObj *pPathObj);
  70. static jeBoolean PathObject_SampleXFormAtTime(PathObj *pPathObj, int TimeLineNdx, float Time, jeBoolean *XFormSet, jeXForm3d *XF);
  71. static char *NoSelection = "< none >";
  72. #define ID_TO_INDEX_MOD_VALUE 100
  73. #define PATHOBJ_ADD_POSITION_TIMELINE_BUTTON 20000
  74. #define PATHOBJ_ADD_PROPERTY_TIMELINE_BUTTON 20001
  75. #define PATHOBJ_SET_SELECTED_KEY 20002
  76. enum PathCommonID
  77. {
  78. PATHOBJ_DETAILS_GROUP = PROPERTY_LOCAL_DATATYPE_START,
  79. PATHOBJ_DETAILS_LOOPTIME,
  80. PATHOBJ_DETAILS_POS_INTERP_LINEAR,
  81. PATHOBJ_DETAILS_POS_INTERP_HERMITE,
  82. PATHOBJ_DETAILS_POS_INTERP_HERMITE_ZERO,
  83. PATHOBJ_DETAILS_POS_END,
  84. PATHOBJ_DETAILS_ROT_INTERP_LINEAR,
  85. PATHOBJ_DETAILS_ROT_INTERP_SLERP,
  86. PATHOBJ_DETAILS_ROT_INTERP_SQUAD,
  87. PATHOBJ_DETAILS_ROT_END,
  88. PATHOBJ_DETAILS_END,
  89. PATHOBJ_NAMELIST,
  90. PATHOBJ_TIMELINE_START,
  91. PATHOBJ_TIMELINE_POS_CHANNEL,
  92. PATHOBJ_TIMELINE_ROT_CHANNEL,
  93. PATHOBJ_TIMELINE_EVENT_CHANNEL,
  94. PATHOBJ_TIMELINE_CUR_TIME,
  95. PATHOBJ_TIMELINE_END,
  96. PATHOBJ_COMMON_END
  97. };
  98. // Property id's for positional channels
  99. enum PathPostionID
  100. {
  101. PATHOBJ_POS = PATHOBJ_COMMON_END,
  102. PATHOBJ_POSX,
  103. PATHOBJ_POSY,
  104. PATHOBJ_POSZ,
  105. PATHOBJ_POS_END,
  106. PATHOBJ_POS_DEL_BUTTON,
  107. };
  108. // Property id's for property channels
  109. enum PathPropertyBaseID
  110. {
  111. PATHOBJ_PROP_PROPNAMELIST = PATHOBJ_COMMON_END,
  112. PATHOBJ_PROP_LAST
  113. };
  114. enum PathPropertyVecID
  115. {
  116. PATHOBJ_VEC = PATHOBJ_PROP_LAST,
  117. PATHOBJ_VECX,
  118. PATHOBJ_VECY,
  119. PATHOBJ_VECZ,
  120. PATHOBJ_VEC_END,
  121. PATHOBJ_VEC_DEL_BUTTON,
  122. };
  123. enum PathPropertyColorID
  124. {
  125. PATHOBJ_COLOR = PATHOBJ_PROP_LAST,
  126. PATHOBJ_COLOR_R,
  127. PATHOBJ_COLOR_G,
  128. PATHOBJ_COLOR_B,
  129. PATHOBJ_COLOR_END,
  130. PATHOBJ_COLOR_DEL_BUTTON,
  131. };
  132. enum PathPropertyFloatID
  133. {
  134. PATHOBJ_FLOAT = PATHOBJ_PROP_LAST,
  135. PATHOBJ_FLOAT_DEL_BUTTON,
  136. };
  137. enum PathPropertyIntID
  138. {
  139. PATHOBJ_INT = PATHOBJ_PROP_LAST,
  140. PATHOBJ_INT_DEL_BUTTON,
  141. };
  142. enum PathPropertyNoneID
  143. {
  144. PATHOBJ_NONE_DEL_BUTTON = PATHOBJ_PROP_LAST,
  145. };
  146. // END: Property id's for property channels
  147. #define DEFAULT_RADIUS 1024.0f
  148. #define MIN_EVENT_STRING_SIZE 64
  149. static jeBitmap *pBitmap = NULL;
  150. #define MAX_OBJ_NAME_LIST 2048
  151. #define MAX_PROP_NAME_LIST 128
  152. typedef struct TimeLineData
  153. {
  154. jeObject *Obj; // Object to modify
  155. int ChannelType; // 0 for positional, 1 for property
  156. int PropDataId; // Primary id for properties
  157. PROPERTY_FIELD_TYPE PropFieldType; // Not necessary if you have the DataId - but it comes in handy
  158. Channel Channels[MAX_CHANNELS]; // cjp modified not to be channel channel..
  159. float SampleTime; // Takes into account looping time
  160. float CurrTime; // Where the time bar actually is. Does not take into account looping time.
  161. float LastTime; // Last position where the time bar actually was.
  162. jeBoolean LoopTime;
  163. int PosInterpType;
  164. int RotInterpType;
  165. char ObjectName[256];
  166. char ObjectPropertyName[256];
  167. char *ObjectNameList[MAX_OBJ_NAME_LIST];
  168. char *PropertyNameList[MAX_PROP_NAME_LIST];
  169. }TimeLineData;
  170. typedef struct PathObj {
  171. jeMotion *Motion[64];
  172. TimeLineData TimeLineList[64];
  173. int TimeLineCount;
  174. int CurTimeLine;
  175. int LastTimeLineModified;
  176. float Time;
  177. jeBoolean PlayMotions;
  178. int RefCnt;
  179. jeBoolean Dirty;
  180. jeWorld *World;
  181. } PathObj;
  182. #define UTIL_MAX_RESOURCE_LENGTH (128)
  183. static char stringbuffer[UTIL_MAX_RESOURCE_LENGTH + 1];
  184. enum PathControlID
  185. {
  186. PATH_CONTROL_POSITION,
  187. PATH_CONTROL_PROPERTY,
  188. };
  189. void Util_StripChar(char *str, char *strip)
  190. {
  191. char *ptr;
  192. assert(str);
  193. assert(strip);
  194. ptr = strstr(str, strip);
  195. if (!ptr)
  196. return;
  197. memmove(ptr, ptr + strlen(strip), strlen(ptr)+1);
  198. }
  199. jeBoolean Util_StrDupManagePtr(char **dest, char *src, int min_size)
  200. {
  201. int len;
  202. assert(dest);
  203. assert(src);
  204. len = strlen(src)+1;
  205. if (*dest)
  206. {
  207. if ( len < min_size )
  208. {
  209. strcpy(*dest, src);
  210. return JE_TRUE;
  211. }
  212. jeRam_Free(*dest);
  213. *dest = NULL;
  214. }
  215. *dest = (char *)jeRam_Allocate(max(min_size, len));
  216. if (*dest == NULL)
  217. {
  218. jeErrorLog_Add( JE_ERR_MEMORY_RESOURCE, NULL );
  219. return JE_FALSE;
  220. }
  221. strcpy(*dest, src);
  222. return JE_TRUE;
  223. }
  224. void TimeEdit_FillTimeLineProperties(PathObj *pPathObj, char *Descr, jeProperty_List *List, int *ListNdx, int TimeLineNdx)
  225. {
  226. int BaseID;
  227. TimeLineData *Element;
  228. char NewDescr[256];
  229. assert(pPathObj);
  230. assert(List);
  231. assert(ListNdx);
  232. BaseID = (TimeLineNdx * ID_TO_INDEX_MOD_VALUE);
  233. Element = &pPathObj->TimeLineList[TimeLineNdx];
  234. sprintf(NewDescr, "Controlling %s", Descr);
  235. jeProperty_FillTimeGroup( &List->pjeProperty[(*ListNdx)], NewDescr, BaseID + PATHOBJ_TIMELINE_START);
  236. (*ListNdx)++;
  237. List->pjeProperty[(*ListNdx)].Type = PROPERTY_CHANNEL_POS_TYPE;
  238. List->pjeProperty[(*ListNdx)].DataId = BaseID + PATHOBJ_TIMELINE_POS_CHANNEL;
  239. List->pjeProperty[(*ListNdx)].DataSize = sizeof(void*);
  240. List->pjeProperty[(*ListNdx)].Data.Ptr = &Element->Channels[CHANNEL_POS];
  241. List->pjeProperty[(*ListNdx)].FieldName = NULL;
  242. (*ListNdx)++;
  243. List->pjeProperty[(*ListNdx)].Type = PROPERTY_CHANNEL_ROT_TYPE;
  244. List->pjeProperty[(*ListNdx)].DataId = BaseID + PATHOBJ_TIMELINE_ROT_CHANNEL;
  245. List->pjeProperty[(*ListNdx)].DataSize = sizeof(void*);
  246. List->pjeProperty[(*ListNdx)].Data.Ptr = &Element->Channels[CHANNEL_ROT];
  247. List->pjeProperty[(*ListNdx)].FieldName = NULL;
  248. (*ListNdx)++;
  249. List->pjeProperty[(*ListNdx)].Type = PROPERTY_CHANNEL_EVENT_TYPE;
  250. List->pjeProperty[(*ListNdx)].DataId = BaseID + PATHOBJ_TIMELINE_EVENT_CHANNEL;
  251. List->pjeProperty[(*ListNdx)].DataSize = sizeof(void*);
  252. List->pjeProperty[(*ListNdx)].Data.Ptr = &Element->Channels[CHANNEL_EVENT];
  253. List->pjeProperty[(*ListNdx)].FieldName = NULL;
  254. (*ListNdx)++;
  255. jeProperty_FillFloat( &List->pjeProperty[(*ListNdx)],
  256. "", Element->CurrTime, BaseID + PATHOBJ_TIMELINE_CUR_TIME, -FLT_MAX, FLT_MAX, 1.0f );
  257. List->pjeProperty[(*ListNdx)].Type = PROPERTY_CURTIME_TYPE;
  258. (*ListNdx)++;
  259. jeProperty_FillGroupEnd( &List->pjeProperty[(*ListNdx)], BaseID + PATHOBJ_TIMELINE_END);
  260. (*ListNdx)++;
  261. }
  262. void TimeEdit_FillDetails(PathObj *pPathObj, jeProperty_List *List, int *ListNdx, int TimeLineNdx)
  263. {
  264. int BaseID;
  265. TimeLineData *Element;
  266. char *InterpLinearStr;
  267. char *InterpHermiteStr;
  268. char *InterpZeroStr;
  269. assert(pPathObj);
  270. assert(List);
  271. assert(ListNdx);
  272. BaseID = (TimeLineNdx * ID_TO_INDEX_MOD_VALUE);
  273. Element = &pPathObj->TimeLineList[TimeLineNdx];
  274. jeProperty_FillGroup( &List->pjeProperty[(*ListNdx)++],
  275. "Details", BaseID + PATHOBJ_DETAILS_GROUP);
  276. jeProperty_FillCheck( &List->pjeProperty[(*ListNdx)++],
  277. "Loop Time:", Element->LoopTime, BaseID + PATHOBJ_DETAILS_LOOPTIME );
  278. if (Element->ChannelType == PATH_CONTROL_PROPERTY)
  279. {
  280. InterpLinearStr = "Prop Interp Linear:";
  281. InterpHermiteStr = "Prop Interp Hermite:";
  282. InterpZeroStr = "Prop Interp Hermite Zero Div:";
  283. }
  284. else
  285. {
  286. InterpLinearStr = "Pos Interp Linear:";
  287. InterpHermiteStr = "Pos Interp Hermite:";
  288. InterpZeroStr = "Pos Interp Hermite Zero Div:";
  289. }
  290. jeProperty_FillRadio( &List->pjeProperty[(*ListNdx)++],
  291. InterpLinearStr, Element->PosInterpType == JE_PATH_INTERPOLATE_LINEAR,
  292. BaseID + PATHOBJ_DETAILS_POS_INTERP_LINEAR);
  293. jeProperty_FillRadio( &List->pjeProperty[(*ListNdx)++],
  294. InterpHermiteStr, Element->PosInterpType == JE_PATH_INTERPOLATE_HERMITE,
  295. BaseID + PATHOBJ_DETAILS_POS_INTERP_HERMITE);
  296. jeProperty_FillRadio( &List->pjeProperty[(*ListNdx)++],
  297. InterpZeroStr, Element->PosInterpType == JE_PATH_INTERPOLATE_HERMITE_ZERO_DERIV,
  298. BaseID + PATHOBJ_DETAILS_POS_INTERP_HERMITE_ZERO);
  299. jeProperty_FillGroupEnd( &List->pjeProperty[(*ListNdx)++],
  300. BaseID + PATHOBJ_DETAILS_POS_END);
  301. if (Element->ChannelType == PATH_CONTROL_POSITION && !Element->Channels[CHANNEL_ROT].Disabled)
  302. {
  303. jeProperty_FillRadio( &List->pjeProperty[(*ListNdx)++],
  304. "Rot Interp Linear:", Element->RotInterpType == JE_PATH_INTERPOLATE_LINEAR,
  305. BaseID + PATHOBJ_DETAILS_ROT_INTERP_LINEAR);
  306. jeProperty_FillRadio( &List->pjeProperty[(*ListNdx)++],
  307. "Rot Interp Slerp:", Element->RotInterpType == JE_PATH_INTERPOLATE_SLERP,
  308. BaseID + PATHOBJ_DETAILS_ROT_INTERP_SLERP);
  309. jeProperty_FillRadio( &List->pjeProperty[(*ListNdx)++],
  310. "Rot Interp Squad:", Element->RotInterpType == JE_PATH_INTERPOLATE_SQUAD,
  311. BaseID + PATHOBJ_DETAILS_ROT_INTERP_SQUAD);
  312. jeProperty_FillGroupEnd( &List->pjeProperty[(*ListNdx)++],
  313. BaseID + PATHOBJ_DETAILS_ROT_END);
  314. }
  315. jeProperty_FillGroupEnd( &List->pjeProperty[(*ListNdx)++],
  316. BaseID + PATHOBJ_DETAILS_GROUP);
  317. }
  318. static jeBoolean PathObject_BuildPropertyList(PathObj * pPathObj, jeProperty_List **List, int *PropertyCount)
  319. {
  320. int i;
  321. int32 NameCount;
  322. int PropertyListIndex;
  323. int BaseID;
  324. jeVec3d Pos = {0,0,0};
  325. TimeLineData *Element;
  326. assert(pPathObj);
  327. assert(List);
  328. assert(*List);
  329. assert(PropertyCount);
  330. PropertyListIndex = 0;
  331. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  332. "Add Position Time Line", PATHOBJ_ADD_POSITION_TIMELINE_BUTTON);
  333. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  334. "Add Property Time Line", PATHOBJ_ADD_PROPERTY_TIMELINE_BUTTON);
  335. for (i = 0; i < pPathObj->TimeLineCount; i++)
  336. {
  337. jeProperty_Data Data;
  338. BaseID = (i * ID_TO_INDEX_MOD_VALUE);
  339. Element = &pPathObj->TimeLineList[i];
  340. memset( &Data, 0, sizeof(Data)); // clear data in case its not set
  341. switch (Element->ChannelType)
  342. {
  343. case PATH_CONTROL_POSITION:
  344. {
  345. const char *CurrName;
  346. NameCount = 0;
  347. PathObject_BuildObjectNameList(pPathObj, i, &NameCount);
  348. CurrName = NULL;
  349. if (Element->Obj)
  350. {
  351. CurrName = jeObject_GetName(Element->Obj);
  352. if (CurrName)
  353. {
  354. strcpy(Element->ObjectName, CurrName);
  355. CurrName = Element->ObjectName;
  356. }
  357. }
  358. if (CurrName == NULL)
  359. CurrName = NoSelection;
  360. jeProperty_FillCombo( &(*List)->pjeProperty[PropertyListIndex++],
  361. "Object:", (char*)CurrName, BaseID + PATHOBJ_NAMELIST, NameCount, Element->ObjectNameList );
  362. TimeEdit_FillDetails(pPathObj, *List, &PropertyListIndex, i);
  363. TimeEdit_FillTimeLineProperties(pPathObj, (char*)CurrName, *List, &PropertyListIndex, i);
  364. if (Element->Obj)
  365. {
  366. jeXForm3d XF;
  367. jeObject_GetXForm(Element->Obj, &XF);
  368. Data.Vector = XF.Translation;
  369. if (Element->Channels[CHANNEL_POS].KeysSelected[0] >= 0 && Element->Channels[CHANNEL_ROT].KeysSelected[0] >= 0)
  370. {
  371. int PosSelNdx,RotSelNdx;
  372. jeXForm3d XF;
  373. // get rotation
  374. RotSelNdx = Element->Channels[CHANNEL_ROT].KeysSelected[0];
  375. XF = Element->Channels[CHANNEL_ROT].KeyData[RotSelNdx].XForm;
  376. // get position
  377. PosSelNdx = Element->Channels[CHANNEL_POS].KeysSelected[0];
  378. Data.Vector = Element->Channels[CHANNEL_POS].KeyData[PosSelNdx].XForm.Translation;
  379. XF.Translation = Element->Channels[CHANNEL_POS].KeyData[PosSelNdx].XForm.Translation;
  380. // set xform
  381. jeObject_SetXForm(Element->Obj, &XF);
  382. }
  383. else
  384. if (Element->Channels[CHANNEL_ROT].KeysSelected[0] >= 0)
  385. {
  386. int RotSelNdx;
  387. jeXForm3d XF, PosXF;
  388. float Time;
  389. jeBoolean Set;
  390. jeVec3d Pos;
  391. // start XF with current position/rotation
  392. jeObject_GetXForm(Element->Obj, &XF);
  393. Pos = XF.Translation;
  394. // get rot keydata
  395. RotSelNdx = Element->Channels[CHANNEL_ROT].KeysSelected[0];
  396. XF = Element->Channels[CHANNEL_ROT].KeyData[RotSelNdx].XForm;
  397. // sample for translation
  398. Time = Element->Channels[CHANNEL_ROT].KeyList[RotSelNdx];
  399. PathObject_SampleXFormAtTime(pPathObj, i, Time, &Set, &PosXF);
  400. if (Set)
  401. {
  402. XF.Translation = PosXF.Translation;
  403. }
  404. else
  405. {
  406. XF.Translation = Pos;
  407. }
  408. Data.Vector = XF.Translation;
  409. // set xform
  410. jeObject_SetXForm(Element->Obj, &XF);
  411. }
  412. else
  413. if (Element->Channels[CHANNEL_POS].KeysSelected[0] >= 0)
  414. {
  415. int PosSelNdx;
  416. jeXForm3d XF, RotXF;
  417. float Time;
  418. jeBoolean Set;
  419. // start XF with current position/rotation
  420. jeObject_GetXForm(Element->Obj, &XF);
  421. PosSelNdx = Element->Channels[CHANNEL_POS].KeysSelected[0];
  422. // sample for rotation
  423. Time = Element->Channels[CHANNEL_POS].KeyList[PosSelNdx];
  424. PathObject_SampleXFormAtTime(pPathObj, i, Time, &Set, &RotXF);
  425. if (Set)
  426. {
  427. XF = RotXF;
  428. }
  429. // set pos
  430. XF.Translation = Element->Channels[CHANNEL_POS].KeyData[PosSelNdx].XForm.Translation;
  431. Data.Vector = XF.Translation;
  432. // set xform
  433. jeObject_SetXForm(Element->Obj, &XF);
  434. }
  435. }
  436. jeProperty_FillVec3dGroup( &(*List)->pjeProperty[PropertyListIndex++],
  437. "Position:", &Data.Vector, BaseID + PATHOBJ_POS);
  438. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  439. "X:", Data.Vector.X, BaseID + PATHOBJ_POSX, -FLT_MAX, FLT_MAX, 1.0f );
  440. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  441. "Y:", Data.Vector.Y, BaseID + PATHOBJ_POSY, -FLT_MAX, FLT_MAX, 1.0f );
  442. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  443. "Z:", Data.Vector.Z, BaseID + PATHOBJ_POSZ, -FLT_MAX, FLT_MAX, 1.0f );
  444. jeProperty_FillGroupEnd( &(*List)->pjeProperty[PropertyListIndex++],
  445. BaseID + PATHOBJ_POS);
  446. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  447. "Delete This Time Line", BaseID + PATHOBJ_POS_DEL_BUTTON);
  448. break;
  449. }
  450. case PATH_CONTROL_PROPERTY:
  451. {
  452. char DescrBuff[256];
  453. const char *CurrObjName;
  454. const char *CurrPropName;
  455. int32 PropertyNameCount, ObjectNameCount;
  456. ObjectNameCount = 0;
  457. PathObject_BuildObjectNameList(pPathObj, i, &ObjectNameCount);
  458. CurrObjName = NULL;
  459. if (Element->Obj)
  460. {
  461. CurrObjName = jeObject_GetName(Element->Obj);
  462. if (CurrObjName)
  463. {
  464. strcpy(Element->ObjectName, CurrObjName);
  465. CurrObjName = Element->ObjectName;
  466. }
  467. }
  468. if (CurrObjName == NULL)
  469. CurrObjName = NoSelection;
  470. jeProperty_FillCombo( &(*List)->pjeProperty[PropertyListIndex++],
  471. "Object:", (char*)CurrObjName, BaseID + PATHOBJ_NAMELIST, ObjectNameCount, Element->ObjectNameList );
  472. TimeEdit_FillDetails(pPathObj, *List, &PropertyListIndex, i);
  473. PropertyNameCount = 0;
  474. PathObject_BuildPropertyNameList(pPathObj, i, &PropertyNameCount);
  475. CurrPropName = NoSelection;
  476. if (Element->Obj && Element->PropDataId >= 0)
  477. {
  478. CurrPropName = Element->ObjectPropertyName;
  479. }
  480. if (strcmp(CurrPropName, NoSelection) == 0)
  481. sprintf(DescrBuff, "%s %s",CurrObjName, CurrPropName);
  482. else
  483. sprintf(DescrBuff, "%s (%s)",CurrObjName, CurrPropName);
  484. TimeEdit_FillTimeLineProperties(pPathObj, DescrBuff, *List, &PropertyListIndex, i);
  485. jeProperty_FillCombo( &(*List)->pjeProperty[PropertyListIndex++],
  486. "Property:", (char*)CurrPropName, BaseID + PATHOBJ_PROP_PROPNAMELIST, PropertyNameCount, Element->PropertyNameList );
  487. if (Element->Obj)
  488. {
  489. // load data from the object
  490. PathObject_GetPropertyInfoFromDataId(pPathObj->World, Element->Obj, Element->PropDataId, NULL, &Data);
  491. }
  492. switch (Element->PropFieldType)
  493. {
  494. default:
  495. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  496. "Delete This Time Line", BaseID + PATHOBJ_NONE_DEL_BUTTON);
  497. break;
  498. case PROPERTY_INT_TYPE:
  499. if (Element->Obj && Element->Channels[CHANNEL_POS].KeysSelected[0] >= 0)
  500. {
  501. int SelNdx = Element->Channels[CHANNEL_POS].KeysSelected[0];
  502. Data.Int = (int)Element->Channels[CHANNEL_POS].KeyData[SelNdx].XForm.Translation.X;
  503. jeObject_SetProperty(Element->Obj, Element->PropDataId, Element->PropFieldType, &Data );
  504. }
  505. jeProperty_FillInt( &(*List)->pjeProperty[PropertyListIndex++],
  506. "Value:", Data.Int, BaseID + PATHOBJ_INT, (float)-INT_MAX, (float)INT_MAX, (float)1 );
  507. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  508. "Delete This Time Line", BaseID + PATHOBJ_INT_DEL_BUTTON);
  509. break;
  510. case PROPERTY_FLOAT_TYPE:
  511. if (Element->Obj && Element->Channels[CHANNEL_POS].KeysSelected[0] >= 0)
  512. {
  513. int SelNdx = Element->Channels[CHANNEL_POS].KeysSelected[0];
  514. Data.Float = Element->Channels[CHANNEL_POS].KeyData[SelNdx].XForm.Translation.X;
  515. jeObject_SetProperty(Element->Obj, Element->PropDataId, Element->PropFieldType, &Data );
  516. }
  517. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  518. "Value:", Data.Float, BaseID + PATHOBJ_FLOAT, -FLT_MAX, FLT_MAX, 1.0f );
  519. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  520. "Delete This Time Line", BaseID + PATHOBJ_FLOAT_DEL_BUTTON);
  521. break;
  522. case PROPERTY_VEC3D_GROUP_TYPE:
  523. if (Element->Obj && Element->Channels[CHANNEL_POS].KeysSelected[0] >= 0)
  524. {
  525. int SelNdx = Element->Channels[CHANNEL_POS].KeysSelected[0];
  526. Data.Vector = Element->Channels[CHANNEL_POS].KeyData[SelNdx].XForm.Translation;
  527. jeObject_SetProperty(Element->Obj, Element->PropDataId, Element->PropFieldType, &Data );
  528. }
  529. jeProperty_FillVec3dGroup( &(*List)->pjeProperty[PropertyListIndex++],
  530. "Vec:", &Data.Vector, BaseID + PATHOBJ_VEC);
  531. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  532. "X:", Data.Vector.X, BaseID + PATHOBJ_VECX, -FLT_MAX, FLT_MAX, 1.0f );
  533. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  534. "Y:", Data.Vector.Y, BaseID + PATHOBJ_VECY, -FLT_MAX, FLT_MAX, 1.0f );
  535. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  536. "Z:", Data.Vector.Z, BaseID + PATHOBJ_VECZ, -FLT_MAX, FLT_MAX, 1.0f );
  537. jeProperty_FillGroupEnd( &(*List)->pjeProperty[PropertyListIndex++],
  538. BaseID + PATHOBJ_VEC);
  539. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  540. "Delete This Time Line", BaseID + PATHOBJ_VEC_DEL_BUTTON);
  541. break;
  542. case PROPERTY_COLOR_GROUP_TYPE:
  543. if (Element->Obj && Element->Channels[CHANNEL_POS].KeysSelected[0] >= 0)
  544. {
  545. int SelNdx = Element->Channels[CHANNEL_POS].KeysSelected[0];
  546. Data.Vector = Element->Channels[CHANNEL_POS].KeyData[SelNdx].XForm.Translation;
  547. jeObject_SetProperty(Element->Obj, Element->PropDataId, Element->PropFieldType, &Data );
  548. }
  549. jeProperty_FillVec3dGroup( &(*List)->pjeProperty[PropertyListIndex++],
  550. "Color:", &Data.Vector, BaseID + PATHOBJ_COLOR);
  551. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  552. "Red:", Data.Vector.X, BaseID + PATHOBJ_COLOR_R, -FLT_MAX, FLT_MAX, 1.0f );
  553. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  554. "Green:", Data.Vector.Y, BaseID + PATHOBJ_COLOR_G, -FLT_MAX, FLT_MAX, 1.0f );
  555. jeProperty_FillFloat( &(*List)->pjeProperty[PropertyListIndex++],
  556. "Blue:", Data.Vector.Z, BaseID + PATHOBJ_COLOR_B, -FLT_MAX, FLT_MAX, 1.0f );
  557. jeProperty_FillGroupEnd( &(*List)->pjeProperty[PropertyListIndex++],
  558. BaseID + PATHOBJ_COLOR);
  559. jeProperty_FillButton( &(*List)->pjeProperty[PropertyListIndex++],
  560. "Delete This Time Line", BaseID + PATHOBJ_COLOR_DEL_BUTTON);
  561. break;
  562. }
  563. }
  564. }
  565. }
  566. *PropertyCount = PropertyListIndex;
  567. return JE_TRUE;
  568. }
  569. static jeObject * PathObject_FindObjectFromName(jeWorld *World, char *NameToFind)
  570. {
  571. jeObject *CurrObject;
  572. const char *Name;
  573. assert (World);
  574. assert (NameToFind);
  575. // loop initializers
  576. CurrObject = NULL;
  577. while (TRUE)
  578. {
  579. CurrObject = jeWorld_GetNextObject(World, CurrObject);
  580. if (CurrObject == NULL)
  581. break;
  582. Name = jeObject_GetName( CurrObject );
  583. if (!Name) continue;
  584. if (stricmp(NameToFind, Name) == 0)
  585. return (CurrObject);
  586. }
  587. return NULL;
  588. }
  589. static jeBoolean PathObject_GetPropertyDataIdFromName(jeWorld *World, jeObject *Obj, char *NameToFind, int32 *PropDataId)
  590. {
  591. jeProperty_List *List;
  592. int i;
  593. char str[1024];
  594. char *CurrGroupName = NULL;
  595. jeBoolean SuppressGroupName;
  596. assert (World);
  597. assert (Obj);
  598. assert (NameToFind);
  599. assert (PropDataId);
  600. if (jeObject_GetPropertyList(Obj, &List) == JE_FALSE)
  601. {
  602. return JE_FALSE;
  603. }
  604. // loop initializers
  605. *PropDataId = -1;
  606. for (i = 0; i < List->jePropertyN; i++)
  607. {
  608. SuppressGroupName = JE_FALSE;
  609. // only list properties that are valid for path-ing
  610. switch (List->pjeProperty[i].Type)
  611. {
  612. case PROPERTY_GROUP_END_TYPE:
  613. CurrGroupName = NULL;
  614. break;
  615. case PROPERTY_GROUP_TYPE:
  616. CurrGroupName = List->pjeProperty[i].FieldName;
  617. break;
  618. case PROPERTY_VEC3D_GROUP_TYPE:
  619. case PROPERTY_COLOR_GROUP_TYPE:
  620. SuppressGroupName = JE_TRUE;
  621. CurrGroupName = List->pjeProperty[i].FieldName;
  622. // no break! falls through on purpose!
  623. case PROPERTY_INT_TYPE:
  624. case PROPERTY_FLOAT_TYPE:
  625. if (!SuppressGroupName && CurrGroupName)
  626. sprintf(str, "%s->%s", CurrGroupName, List->pjeProperty[i].FieldName);
  627. else
  628. strcpy(str, List->pjeProperty[i].FieldName);
  629. if (strcmp(NameToFind, str) == 0)
  630. {
  631. *PropDataId = List->pjeProperty[i].DataId;
  632. jeProperty_ListDestroy(&List);
  633. return JE_TRUE;
  634. }
  635. break;
  636. }
  637. }
  638. jeProperty_ListDestroy(&List);
  639. return JE_FALSE;
  640. }
  641. static jeBoolean PathObject_BuildPropertyNameList(PathObj *pPathObj, int TimeLineNdx, int32 *NameCount)
  642. {
  643. jeProperty_List *List;
  644. int i;
  645. TimeLineData *td;
  646. char *CurrGroupName = NULL;
  647. char str[1024];
  648. jeBoolean SuppressGroupName;
  649. assert (pPathObj);
  650. assert (NameCount);
  651. td = &pPathObj->TimeLineList[TimeLineNdx];
  652. // loop initializers
  653. *NameCount = 0;
  654. Util_StrDupManagePtr(&td->PropertyNameList[*NameCount], NoSelection, 32);
  655. (*NameCount)++;
  656. if (!td->Obj)
  657. {
  658. return JE_TRUE;
  659. }
  660. if (jeObject_GetPropertyList(td->Obj, &List) == JE_FALSE)
  661. {
  662. return JE_FALSE;
  663. }
  664. for (i = 0; i < List->jePropertyN; i++)
  665. {
  666. SuppressGroupName = JE_FALSE;
  667. // only list properties that are valid for path-ing
  668. switch (List->pjeProperty[i].Type)
  669. {
  670. case PROPERTY_GROUP_END_TYPE:
  671. CurrGroupName = NULL;
  672. break;
  673. case PROPERTY_GROUP_TYPE:
  674. CurrGroupName = List->pjeProperty[i].FieldName;
  675. break;
  676. case PROPERTY_VEC3D_GROUP_TYPE:
  677. case PROPERTY_COLOR_GROUP_TYPE:
  678. SuppressGroupName = JE_TRUE;
  679. CurrGroupName = List->pjeProperty[i].FieldName;
  680. // no break! falls through on purpose!
  681. case PROPERTY_INT_TYPE:
  682. case PROPERTY_FLOAT_TYPE:
  683. if (td->PropDataId != List->pjeProperty[i].DataId)
  684. {
  685. if (PathObject_ValidateObject(pPathObj, td->ChannelType, td->Obj, List->pjeProperty[i].DataId) == JE_FALSE)
  686. break;
  687. }
  688. if (!SuppressGroupName && CurrGroupName)
  689. sprintf(str, "%s->%s", CurrGroupName, List->pjeProperty[i].FieldName);
  690. else
  691. strcpy(str, List->pjeProperty[i].FieldName);
  692. Util_StrDupManagePtr(&td->PropertyNameList[*NameCount], str, 32);
  693. assert(td->PropertyNameList[*NameCount]);
  694. (*NameCount)++;
  695. break;
  696. }
  697. }
  698. jeProperty_ListDestroy(&List);
  699. return JE_TRUE;
  700. }
  701. static jeBoolean PathObject_ObjectHasProperties(PathObj *pPathObj, jeObject *Obj, jeBoolean *HasProperties)
  702. {
  703. jeProperty_List *List;
  704. int i;
  705. assert (pPathObj);
  706. assert (HasProperties);
  707. *HasProperties = JE_FALSE;
  708. if (jeObject_GetPropertyList(Obj, &List) == JE_FALSE)
  709. {
  710. return JE_FALSE;
  711. }
  712. for (i = 0; i < List->jePropertyN; i++)
  713. {
  714. switch (List->pjeProperty[i].Type)
  715. {
  716. case PROPERTY_VEC3D_GROUP_TYPE:
  717. case PROPERTY_COLOR_GROUP_TYPE:
  718. case PROPERTY_INT_TYPE:
  719. case PROPERTY_FLOAT_TYPE:
  720. *HasProperties = JE_TRUE;
  721. break;
  722. }
  723. if (*HasProperties)
  724. break;
  725. }
  726. jeProperty_ListDestroy(&List);
  727. return JE_TRUE;
  728. }
  729. static jeBoolean PathObject_GetPropertyInfoFromDataId(jeWorld *World, jeObject *Obj, int32 DataId, int32 *Type, jeProperty_Data *Data)
  730. {
  731. jeProperty_List *List;
  732. int i;
  733. assert (World);
  734. assert (Obj);
  735. if (jeObject_GetPropertyList(Obj, &List) == JE_FALSE)
  736. {
  737. return JE_FALSE;
  738. }
  739. for (i = 0; i < List->jePropertyN; i++)
  740. {
  741. if (List->pjeProperty[i].DataId == DataId)
  742. {
  743. if (Type)
  744. *Type = List->pjeProperty[i].Type;
  745. if (Data)
  746. *Data = List->pjeProperty[i].Data;
  747. jeProperty_ListDestroy(&List);
  748. return JE_TRUE;
  749. }
  750. }
  751. jeProperty_ListDestroy(&List);
  752. return (JE_FALSE);
  753. }
  754. static jeBoolean PathObject_ValidateObject(PathObj *pPathObj, int ChannelType, jeObject *Obj, int PropID)
  755. {
  756. int i;
  757. assert (pPathObj);
  758. assert (Obj);
  759. // make sure an object/property is selected that has not already been selected for this PathObject
  760. for (i = 0; i < pPathObj->TimeLineCount; i++)
  761. {
  762. if (pPathObj->TimeLineList[i].ChannelType == ChannelType)
  763. {
  764. if (pPathObj->TimeLineList[i].ChannelType == PATH_CONTROL_POSITION)
  765. {
  766. if (pPathObj->TimeLineList[i].Obj == Obj)
  767. {
  768. return JE_FALSE;
  769. }
  770. }
  771. else
  772. if (pPathObj->TimeLineList[i].ChannelType == PATH_CONTROL_PROPERTY)
  773. {
  774. if (pPathObj->TimeLineList[i].Obj == Obj && pPathObj->TimeLineList[i].PropDataId == PropID)
  775. {
  776. return JE_FALSE;
  777. }
  778. }
  779. }
  780. }
  781. return JE_TRUE;
  782. }
  783. static jeBoolean PathObject_BuildObjectNameList(PathObj *pPathObj, int TimeLineNdx, int32 *NameCount)
  784. {
  785. jeObject *CurrObject;
  786. char *Name,*TypeName;
  787. TimeLineData *td;
  788. assert (pPathObj);
  789. assert (NameCount);
  790. td = &pPathObj->TimeLineList[TimeLineNdx];
  791. // loop initializers
  792. CurrObject = NULL;
  793. *NameCount = 0;
  794. Util_StrDupManagePtr(&td->ObjectNameList[*NameCount], NoSelection, 32);
  795. (*NameCount)++;
  796. while (TRUE)
  797. {
  798. CurrObject = jeWorld_GetNextObject(pPathObj->World, CurrObject);
  799. if (CurrObject == NULL)
  800. break;
  801. Name = (char *)jeObject_GetName( CurrObject );
  802. if (Name == NULL)
  803. continue;
  804. TypeName = (char*)jeObject_GetTypeName(CurrObject);
  805. if (TypeName)
  806. {
  807. // don't look at PathObjects
  808. if ( stricmp(TypeName, "PathObject") == 0)
  809. {
  810. continue;
  811. }
  812. }
  813. if (td->Obj != CurrObject)
  814. {
  815. if (td->ChannelType == PATH_CONTROL_PROPERTY)
  816. {
  817. jeBoolean HasProperties;
  818. PathObject_ObjectHasProperties(pPathObj, CurrObject, &HasProperties);
  819. if (!HasProperties)
  820. continue;
  821. }
  822. else
  823. if (td->ChannelType == PATH_CONTROL_POSITION)
  824. {
  825. int obj_flags = jeObject_GetXFormModFlags(CurrObject);
  826. if (obj_flags == 0)
  827. {
  828. continue;
  829. }
  830. if (PathObject_ValidateObject(pPathObj, td->ChannelType, CurrObject, -1) == JE_FALSE)
  831. continue;
  832. }
  833. }
  834. Util_StrDupManagePtr(&td->ObjectNameList[*NameCount], Name, 32);
  835. assert(td->ObjectNameList[*NameCount]);
  836. (*NameCount)++;
  837. }
  838. return JE_TRUE;
  839. }
  840. ///////////////////////////////////////////////////////////////////////////////
  841. //
  842. // Object ATTACH, DETACH Routines
  843. //
  844. ///////////////////////////////////////////////////////////////////////////////
  845. void Destroy_Class( void )
  846. {
  847. }
  848. #ifdef WIN32
  849. void Init_Class( HINSTANCE hInst)
  850. #endif
  851. #ifdef BUILD_BE
  852. void Init_Class( image_id hInst)
  853. #endif
  854. {
  855. //ParentWnd = hWnd;
  856. hInstance = hInst;
  857. }
  858. ///////////////////////////////////////////////////////////////////////////////
  859. //
  860. // Object INTERFACE Routines
  861. //
  862. ///////////////////////////////////////////////////////////////////////////////
  863. void * JETCC CreateInstance()
  864. {
  865. PathObj *pPathObj;
  866. pPathObj = JE_RAM_ALLOCATE_STRUCT( PathObj );
  867. if( pPathObj == NULL )
  868. goto CI_ERROR;
  869. memset(pPathObj, 0, sizeof(*pPathObj));
  870. pPathObj->RefCnt = 1;
  871. return( pPathObj );
  872. CI_ERROR:
  873. if (pPathObj)
  874. jeRam_Free( pPathObj );
  875. return( NULL );
  876. }
  877. void JETCC CreateRef(void * Instance)
  878. {
  879. PathObj *pPathObj = (PathObj*)Instance;
  880. assert( Instance );
  881. pPathObj->RefCnt++;
  882. }
  883. static jeBoolean PathObject_ProcessEvents(PathObj *pPathObj, int TimeLineNdx, float StartTime, float EndTime)
  884. {
  885. float Time;
  886. char *EventString;
  887. TimeLineData *td;
  888. jeMotion *Motion;
  889. jeObject *Obj;
  890. int MessageID;
  891. char *StrPtr;
  892. char *ptr;
  893. Object_EventData ed;
  894. //assert(StartTime <= EndTime);
  895. td = &pPathObj->TimeLineList[TimeLineNdx];
  896. Motion = pPathObj->Motion[TimeLineNdx];
  897. jeMotion_SetupEventIterator(Motion, StartTime, EndTime);
  898. while( jeMotion_GetNextEvent( Motion, &Time, (const char **)&EventString ) )
  899. {
  900. Obj = td->Obj;
  901. MessageID = 0;
  902. StrPtr = EventString;
  903. if (ptr = strstr(EventString,";")) // ptr now points to the semi-colon
  904. {
  905. char ObjName[256];
  906. sscanf(EventString,"%s %d", ObjName, &MessageID);
  907. Obj = PathObject_FindObjectFromName(pPathObj->World, ObjName);
  908. if (!Obj)
  909. return JE_FALSE;
  910. StrPtr = &ptr[1]; // move one past the semi-colon
  911. while(*StrPtr == ' ') // get rid of leading blanks
  912. StrPtr++;
  913. }
  914. ed.EventType = MessageID;
  915. ed.FromObj = td->Obj;
  916. ed.Args = StrPtr;
  917. jeObject_SendMessage(Obj, 0, &ed);
  918. }
  919. return JE_TRUE;
  920. }
  921. void JETCC PathObject_FreeTimeLine(PathObj *pPathObj, int TimeLineNdx)
  922. {
  923. int k;
  924. int i = TimeLineNdx;
  925. TimeLineData *td;
  926. assert(pPathObj);
  927. assert(TimeLineNdx >= 0);
  928. td = &pPathObj->TimeLineList[TimeLineNdx];
  929. if (pPathObj->Motion[i])
  930. jeMotion_Destroy(&pPathObj->Motion[i]);
  931. if (td->Obj)
  932. jeObject_Destroy(&td->Obj);
  933. for (k = 0; k < td->Channels[CHANNEL_EVENT].KeyCount; k++)
  934. {
  935. if (td->Channels[CHANNEL_EVENT].KeyData[k].String)
  936. {
  937. jeRam_Free(td->Channels[CHANNEL_EVENT].KeyData[k].String);
  938. td->Channels[CHANNEL_EVENT].KeyData[k].String = NULL;
  939. }
  940. }
  941. for (i = 0; i < MAX_OBJ_NAME_LIST; i++)
  942. {
  943. if (td->ObjectNameList[i])
  944. {
  945. jeRam_Free(td->ObjectNameList[i]);
  946. td->ObjectNameList[i] = NULL;
  947. }
  948. }
  949. for (i = 0; i < MAX_PROP_NAME_LIST; i++)
  950. {
  951. if (td->PropertyNameList[i])
  952. {
  953. jeRam_Free(td->PropertyNameList[i]);
  954. td->PropertyNameList[i] = NULL;
  955. }
  956. }
  957. }
  958. jeBoolean JETCC Destroy(void **pInstance)
  959. {
  960. PathObj **hPathObj = (PathObj**)pInstance;
  961. PathObj *pPathObj = *hPathObj;
  962. assert( pInstance );
  963. assert( pPathObj->RefCnt > 0 );
  964. pPathObj->RefCnt--;
  965. if( pPathObj->RefCnt == 0 )
  966. {
  967. int i;
  968. for (i = 0; i < pPathObj->TimeLineCount; i++)
  969. {
  970. PathObject_FreeTimeLine(pPathObj, i);
  971. }
  972. jeRam_Free( pPathObj );
  973. }
  974. return JE_TRUE;
  975. }
  976. jeBoolean JETCC Render(const void * Instance, const jeWorld * pWorld, const jeEngine *Engine, const jeCamera *Camera, const jeFrustum *CameraSpaceFrustum, jeObject_RenderFlags RenderFlags)
  977. {
  978. PathObj *pPathObj = (PathObj*)Instance;
  979. assert( Instance );
  980. assert( pWorld );
  981. assert( Engine );
  982. assert( Camera );
  983. return( JE_TRUE );
  984. }
  985. jeBoolean JETCC AttachWorld( void * Instance, jeWorld * pWorld )
  986. {
  987. PathObj *pPathObj = (PathObj*)Instance;
  988. assert( Instance );
  989. pPathObj->World = pWorld;
  990. return( JE_TRUE );
  991. }
  992. jeBoolean JETCC DettachWorld( void * Instance, jeWorld * pWorld )
  993. {
  994. PathObj *pPathObj = (PathObj*)Instance;
  995. assert( Instance );
  996. pPathObj->World = NULL;
  997. return( JE_TRUE );
  998. }
  999. jeBoolean JETCC AttachEngine ( void * Instance, jeEngine *Engine )
  1000. {
  1001. PathObj *pPathObj = (PathObj*)Instance;
  1002. assert( Instance );
  1003. assert( Engine );
  1004. return JE_TRUE;
  1005. Instance;
  1006. }
  1007. jeBoolean JETCC DettachEngine( void * Instance, jeEngine *Engine )
  1008. {
  1009. assert( Instance );
  1010. return( JE_TRUE );
  1011. Instance;
  1012. }
  1013. jeBoolean JETCC AttachSoundSystem( void * Instance, jeSound_System *SoundSystem )
  1014. {
  1015. PathObj *pPathObj = (PathObj*)Instance;
  1016. assert( Instance );
  1017. return( JE_TRUE );
  1018. }
  1019. jeBoolean JETCC DettachSoundSystem( void * Instance, jeSound_System *SoundSystem )
  1020. {
  1021. PathObj *pPathObj = (PathObj*)Instance;
  1022. assert( Instance );
  1023. return( JE_TRUE );
  1024. SoundSystem;
  1025. }
  1026. jeBoolean JETCC Collision(const void *Object, const jeExtBox *Box, const jeVec3d *Front, const jeVec3d *Back, jeVec3d *Impact, jePlane *Plane)
  1027. {
  1028. return( JE_FALSE );
  1029. }
  1030. jeBoolean JETCC SetMaterial(void * Instance,const jeBitmap *Bmp,const jeRGBA * Color)
  1031. {
  1032. return( JE_TRUE );
  1033. }
  1034. jeBoolean JETCC GetMaterial(const void * Instance,jeBitmap **pBmp,jeRGBA * Color)
  1035. {
  1036. return( JE_TRUE );
  1037. }
  1038. jeBoolean JETCC GetExtBox(const void * Instance,jeExtBox *BBox)
  1039. {
  1040. /*
  1041. jeVec3d Point = {0,0,0};
  1042. assert( Instance );
  1043. assert( BBox );
  1044. BBox->Min.X = 0;
  1045. BBox->Min.Y = 0;
  1046. BBox->Min.Z = 0;
  1047. BBox->Max.X = 0;
  1048. BBox->Max.Y = 0;
  1049. BBox->Max.Z = 0;
  1050. jeExtBox_Set ( BBox,
  1051. Point.X-5.0f, Point.Y-5.0f, Point.Z-5.0f,
  1052. Point.X+5.0f, Point.Y+5.0f, Point.Z+5.0f);
  1053. */
  1054. return JE_FALSE;
  1055. //return JE_TRUE;
  1056. Instance, BBox;
  1057. }
  1058. ////////////////////////////////////////////////////////////////////////////////////////
  1059. //
  1060. // ObjUtil_ReadString()
  1061. //
  1062. ////////////////////////////////////////////////////////////////////////////////////////
  1063. jeBoolean ObjUtil_ReadString(
  1064. jeVFile *File, // file to read from
  1065. char **String ) // where to save string pointer
  1066. {
  1067. // locals
  1068. int Size;
  1069. jeBoolean Result = JE_TRUE;
  1070. // ensure valid data
  1071. assert( File != NULL );
  1072. assert( String != NULL );
  1073. // read string
  1074. Result &= jeVFile_Read( File, &( Size ), sizeof( Size ) );
  1075. if ( ( Size > 0 ) && ( Result == JE_TRUE ) )
  1076. {
  1077. *String = (char *)jeRam_Allocate( Size );
  1078. if ( *String == NULL )
  1079. {
  1080. return JE_FALSE;
  1081. }
  1082. Result &= jeVFile_Read( File, *String, Size );
  1083. }
  1084. // all done
  1085. return Result;
  1086. } // ObjUtil_ReadString()
  1087. ////////////////////////////////////////////////////////////////////////////////////////
  1088. //
  1089. // ObjUtil_WriteString()
  1090. //
  1091. ////////////////////////////////////////////////////////////////////////////////////////
  1092. jeBoolean ObjUtil_WriteString(
  1093. jeVFile *File, // file to write to
  1094. char *String ) // string to write out
  1095. {
  1096. // locals
  1097. int Size;
  1098. jeBoolean Result = JE_TRUE;
  1099. // ensure valid data
  1100. assert( File != NULL );
  1101. assert( String != NULL );
  1102. // write out complete
  1103. Size = strlen( String ) + 1;
  1104. assert( Size > 0 );
  1105. Result &= jeVFile_Write( File, &Size, sizeof( Size ) );
  1106. Result &= jeVFile_Write( File, String, Size );
  1107. // all done
  1108. return Result;
  1109. } // ObjUtil_WriteString()
  1110. void * JETCC CreateFromFile(jeVFile * File, jePtrMgr *PtrMgr)
  1111. {
  1112. PathObj *Object;
  1113. jeBoolean Result = JE_TRUE;
  1114. int i,k;
  1115. int ProcCount;
  1116. int Ver;
  1117. BYTE Version;
  1118. uint32 Tag;
  1119. OutputDebugString("PathObject\n");
  1120. // ensure valid data
  1121. assert( File != NULL );
  1122. assert( PtrMgr != NULL );
  1123. Object = (PathObj *)CreateInstance();
  1124. if (!Object) goto ExitErr;
  1125. if(!jeVFile_Read(File, &Tag, sizeof(Tag)))
  1126. {
  1127. jeErrorLog_Add( JE_ERR_FILEIO_READ, "PathObject_CreateFromFile:Tag" );
  1128. goto ExitErr;
  1129. }
  1130. if (Tag == FILE_UNIQUE_ID)
  1131. {
  1132. if (!jeVFile_Read(File, &Version, sizeof(Version)))
  1133. {
  1134. jeErrorLog_Add( JE_ERR_FILEIO_READ, "PathObject_CreateFromFile:Version" );
  1135. goto ExitErr;
  1136. }
  1137. }
  1138. else
  1139. {
  1140. //for backwards compatibility with old object format
  1141. jeVFile_Seek(File,-((int)sizeof(Tag)),JE_VFILE_SEEKCUR);
  1142. if (!jeVFile_Read(File, &Ver, sizeof(Ver)))
  1143. goto ExitErr;
  1144. if (!jeVFile_Read(File, &Ver, sizeof(Ver)))
  1145. goto ExitErr;
  1146. Version = 1;
  1147. }
  1148. if (Version >= 1)
  1149. {
  1150. if (!jeVFile_Read(File, &Object->TimeLineCount, sizeof(Object->TimeLineCount)))
  1151. goto ExitErr;
  1152. if (!jeVFile_Read(File, &Object->CurTimeLine, sizeof(Object->CurTimeLine)))
  1153. goto ExitErr;
  1154. if (!jeVFile_Read(File, &Object->LastTimeLineModified, sizeof(Object->LastTimeLineModified)))
  1155. goto ExitErr;
  1156. if (!jeVFile_Read(File, &Object->Time, sizeof(Object->Time)))
  1157. goto ExitErr;
  1158. if (!jeVFile_Read(File, &Object->PlayMotions, sizeof(Object->PlayMotions)))
  1159. goto ExitErr;
  1160. }
  1161. for (i = 0; i < Object->TimeLineCount; i++)
  1162. {
  1163. // read an entire time line
  1164. if (!jeVFile_Read(File, &Object->TimeLineList[i], sizeof(Object->TimeLineList[0])))
  1165. goto ExitErr;
  1166. // clear keydata for EVENTS
  1167. memset(Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData, 0, sizeof(Object->TimeLineList[0].Channels[0].KeyData));
  1168. // clear allocated pointer values
  1169. memset(Object->TimeLineList[i].ObjectNameList, 0, sizeof(Object->TimeLineList[0].ObjectNameList));
  1170. memset(Object->TimeLineList[i].PropertyNameList, 0, sizeof(Object->TimeLineList[0].PropertyNameList));
  1171. ProcCount = i;
  1172. // read individual event keys
  1173. for (k = 0; k < Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyCount; k++)
  1174. {
  1175. char *Buff;
  1176. if (!ObjUtil_ReadString(File, &Buff))
  1177. goto ExitErr;
  1178. // KeyData.String will be null
  1179. if (Util_StrDupManagePtr(&Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData[k].String, Buff, MIN_EVENT_STRING_SIZE) == JE_FALSE)
  1180. goto ExitErr;
  1181. jeRam_Free (Buff);
  1182. }
  1183. Object->TimeLineList[i].Obj = jeObject_CreateFromFile(File, PtrMgr);
  1184. }
  1185. PathObject_BuildAllMotions(Object);
  1186. return (Object);
  1187. ExitErr:
  1188. printf("Error occured in CreateFromFile (PathObject)\n");
  1189. if (Object)
  1190. {
  1191. Destroy((void **)&Object);
  1192. }
  1193. for (i = 0; i < ProcCount; i++)
  1194. {
  1195. for (k = 0; k < Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyCount; k++)
  1196. {
  1197. if (Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData[k].String)
  1198. {
  1199. jeRam_Free(Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData[k].String);
  1200. Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData[k].String = NULL;
  1201. }
  1202. }
  1203. }
  1204. return (NULL);
  1205. }
  1206. jeBoolean JETCC WriteToFile(
  1207. const void *Instance,
  1208. jeVFile *File,
  1209. jePtrMgr *PtrMgr )
  1210. {
  1211. // locals
  1212. PathObj *Object;
  1213. int i,k;
  1214. BYTE Version = PATHOBJ_VERSION;
  1215. uint32 Tag = FILE_UNIQUE_ID;
  1216. int iObjects=0; // must be same type as Object->TimeLineCount JH
  1217. // ensure valid data
  1218. assert( Instance != NULL );
  1219. assert( File != NULL );
  1220. assert( PtrMgr != NULL );
  1221. // get object data
  1222. Object = (PathObj *)Instance;
  1223. // count valid objects (added JH 2.5.2000)
  1224. for (i = 0; i < Object->TimeLineCount; i++)
  1225. {
  1226. if (Object->TimeLineList[i].Obj!=NULL) iObjects++;
  1227. }
  1228. if (!jeVFile_Write(File, &Tag,sizeof(Tag)))
  1229. goto ExitErr;
  1230. if (!jeVFile_Write(File, &Version, sizeof(Version)))
  1231. goto ExitErr;
  1232. if (!jeVFile_Write(File, &iObjects, sizeof(iObjects)))
  1233. goto ExitErr;
  1234. if (!jeVFile_Write(File, &Object->CurTimeLine, sizeof(Object->CurTimeLine)))
  1235. goto ExitErr;
  1236. if (!jeVFile_Write(File, &Object->LastTimeLineModified, sizeof(Object->LastTimeLineModified)))
  1237. goto ExitErr;
  1238. if (!jeVFile_Write(File, &Object->Time, sizeof(Object->Time)))
  1239. goto ExitErr;
  1240. if (!jeVFile_Write(File, &Object->PlayMotions, sizeof(Object->PlayMotions)))
  1241. goto ExitErr;
  1242. for (i = 0; i < iObjects; i++)
  1243. {
  1244. // write a whole time line
  1245. if (Object->TimeLineList[i].Obj!=NULL)
  1246. {
  1247. if (!jeVFile_Write(File, &Object->TimeLineList[i], sizeof(Object->TimeLineList[0])))
  1248. goto ExitErr;
  1249. // MAKE SURE AND SAVE THE CHANNEL STRINGS SEPERATELY!!!!!!!!
  1250. // save the individual key strings
  1251. for (k = 0; k < Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyCount; k++)
  1252. {
  1253. if (Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData[k].String)
  1254. {
  1255. char *cp;
  1256. int len;
  1257. cp = Object->TimeLineList[i].Channels[CHANNEL_EVENT].KeyData[k].String;
  1258. len = strlen(cp)+1;
  1259. if (!ObjUtil_WriteString(File, cp))
  1260. goto ExitErr;
  1261. }
  1262. else // No Text then write nothing
  1263. {
  1264. if (!ObjUtil_WriteString(File, ""))
  1265. goto ExitErr;
  1266. }
  1267. }
  1268. if (!jeObject_WriteToFile(Object->TimeLineList[i].Obj, File, PtrMgr))
  1269. goto ExitErr;
  1270. }
  1271. }
  1272. // all done
  1273. return TRUE;
  1274. ExitErr:
  1275. jeErrorLog_Add( JE_ERR_SYSTEM_RESOURCE, NULL );
  1276. return JE_FALSE;
  1277. } // WriteToFile()
  1278. jeBoolean PathObject_InitAddTimeLine(PathObj *pPathObj, int ChannelType, int ChannelFlags)
  1279. {
  1280. int ThisTimeLine;
  1281. int i;
  1282. assert(pPathObj);
  1283. assert(ChannelType == PATH_CONTROL_POSITION || ChannelType == PATH_CONTROL_PROPERTY);
  1284. ThisTimeLine = pPathObj->TimeLineCount;
  1285. memset(&pPathObj->TimeLineList[ThisTimeLine], 0, sizeof(pPathObj->TimeLineList[0]));
  1286. pPathObj->TimeLineList[ThisTimeLine].ChannelType = ChannelType;
  1287. pPathObj->TimeLineList[ThisTimeLine].PropDataId = -1;
  1288. pPathObj->TimeLineList[ThisTimeLine].PosInterpType = JE_PATH_INTERPOLATE_HERMITE;
  1289. pPathObj->TimeLineList[ThisTimeLine].RotInterpType = JE_PATH_INTERPOLATE_SQUAD;
  1290. for (i = 0; i < MAX_CHANNELS; i++)
  1291. {
  1292. pPathObj->TimeLineList[ThisTimeLine].Channels[i].Disabled = JE_TRUE;
  1293. if (ChannelFlags & 1<<i)
  1294. {
  1295. memset(pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeyData, 0, sizeof(pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeyData));
  1296. memset(pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeyList, 0, sizeof(pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeyList));
  1297. memset(pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeysSelected, -1, sizeof(pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeysSelected));
  1298. pPathObj->TimeLineList[ThisTimeLine].Channels[i].KeyCount = 0;
  1299. }
  1300. }
  1301. pPathObj->TimeLineCount++;
  1302. return JE_TRUE;
  1303. }
  1304. jeBoolean PathObject_EnableTimeLine(PathObj *pPathObj, int TimeLineNdx, int ChannelFlags)
  1305. {
  1306. int i;
  1307. assert(pPathObj);
  1308. assert(TimeLineNdx >= 0 && TimeLineNdx <= 64);
  1309. for (i = 0; i < MAX_CHANNELS; i++)
  1310. {
  1311. if (ChannelFlags & 1<<i)
  1312. {
  1313. pPathObj->TimeLineList[TimeLineNdx].Channels[i].Disabled = JE_FALSE;
  1314. }
  1315. }
  1316. return JE_TRUE;
  1317. }
  1318. jeBoolean JETCC GetPropertyList(void * Instance, jeProperty_List **List)
  1319. {
  1320. PathObj *pPathObj = (PathObj*)Instance;
  1321. int PropertyCount;
  1322. jeProperty_List *LocalList;
  1323. assert(Instance);
  1324. assert(List);
  1325. // Create a big list and build into that
  1326. LocalList = jeProperty_ListCreate(2048);
  1327. PathObject_BuildPropertyList(pPathObj, &LocalList, &PropertyCount);
  1328. LocalList->pjeProperty = JE_RAM_REALLOC_ARRAY( LocalList->pjeProperty, jeProperty, PropertyCount);
  1329. LocalList->jePropertyN = PropertyCount;
  1330. LocalList->bDirty = pPathObj->Dirty;
  1331. pPathObj->Dirty = JE_FALSE;
  1332. *List = LocalList;
  1333. if( *List == NULL )
  1334. return( JE_FALSE );
  1335. return( JE_TRUE );
  1336. }
  1337. jeBoolean PathObject_IsLooped(PathObj *pPathObj, int TimeLineNdx)
  1338. {
  1339. int i,k;
  1340. float FirstPosTime = 9999999.9f, LastPosTime = -1.0f;
  1341. float FirstRotTime = 9999999.9f, LastRotTime = -1.0f;
  1342. int FirstPosNdx = -1, LastPosNdx = -1;
  1343. int FirstRotNdx = -1, LastRotNdx = -1;
  1344. TimeLineData *td;
  1345. jeBoolean LoopValid = JE_TRUE;
  1346. // this routine determines if the last and first key data is the same
  1347. // does a seperate test for pos and rot
  1348. td = &pPathObj->TimeLineList[TimeLineNdx];
  1349. // find first and last pos/rot
  1350. if (!td->Channels[CHANNEL_POS].Disabled)
  1351. {
  1352. i = CHANNEL_POS;
  1353. for (k = 0; k < td->Channels[i].KeyCount; k++)
  1354. {
  1355. if (td->Channels[i].KeyList[k] < FirstPosTime)
  1356. {
  1357. FirstPosTime = td->Channels[i].KeyList[k];
  1358. FirstPosNdx = k;
  1359. }
  1360. if (td->Channels[i].KeyList[k] > LastPosTime)
  1361. {
  1362. LastPosTime = td->Channels[i].KeyList[k];
  1363. LastPosNdx = k;
  1364. }
  1365. }
  1366. if (FirstPosNdx != LastPosNdx && FirstPosNdx >= 0)
  1367. {
  1368. if (memcmp(&td->Channels[i].KeyData[FirstPosNdx].XForm, &td->Channels[i].KeyData[LastPosNdx].XForm, sizeof(jeXForm3d)))
  1369. {
  1370. return JE_FALSE;
  1371. }
  1372. }
  1373. }
  1374. // find first and last pos/rot
  1375. if (!td->Channels[CHANNEL_ROT].Disabled)
  1376. {
  1377. i = CHANNEL_ROT;
  1378. for (k = 0; k < td->Channels[i].KeyCount; k++)
  1379. {
  1380. if (td->Channels[i].KeyList[k] < FirstRotTime)
  1381. {
  1382. FirstRotTime = td->Channels[i].KeyList[k];
  1383. FirstRotNdx = k;
  1384. }
  1385. if (td->Channels[i].KeyList[k] > LastRotTime)
  1386. {
  1387. LastRotTime = td->Channels[i].KeyList[k];
  1388. LastRotNdx = k;
  1389. }
  1390. }
  1391. if (FirstRotNdx != LastRotNdx && FirstRotNdx >= 0)
  1392. {
  1393. if (memcmp(&td->Channels[i].KeyData[FirstRotNdx].XForm, &td->Channels[i].KeyData[LastRotNdx].XForm, sizeof(jeXForm3d)))
  1394. {
  1395. return JE_FALSE;