SceneLoader.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. #include "Base.h"
  2. #include "Game.h"
  3. #include "Bundle.h"
  4. #include "SceneLoader.h"
  5. namespace gameplay
  6. {
  7. std::map<std::string, Properties*> SceneLoader::_propertiesFromFile;
  8. std::vector<SceneLoader::SceneAnimation> SceneLoader::_animations;
  9. std::vector<SceneLoader::SceneNode> SceneLoader::_sceneNodes;
  10. std::string SceneLoader::_path;
  11. Scene* SceneLoader::load(const char* filePath)
  12. {
  13. assert(filePath);
  14. // Load the scene properties from file.
  15. Properties* properties = Properties::create(filePath);
  16. assert(properties);
  17. if (properties == NULL)
  18. {
  19. WARN_VARG("Failed to load scene file: %s", filePath);
  20. return NULL;
  21. }
  22. // Check if the properties object is valid and has a valid namespace.
  23. Properties* sceneProperties = properties->getNextNamespace();
  24. assert(sceneProperties);
  25. if (!sceneProperties || !(strcmp(sceneProperties->getNamespace(), "scene") == 0))
  26. {
  27. WARN("Failed to load scene from properties object: must be non-null object and have namespace equal to 'scene'.");
  28. SAFE_DELETE(properties);
  29. return NULL;
  30. }
  31. // Get the path to the main GPB.
  32. _path = sceneProperties->getString("path");
  33. // Build the node URL/property and animation reference tables and load the referenced files.
  34. buildReferenceTables(sceneProperties);
  35. loadReferencedFiles();
  36. // Load the main scene data from GPB and apply the global scene properties.
  37. Scene* scene = loadMainSceneData(sceneProperties);
  38. if (!scene)
  39. {
  40. SAFE_DELETE(properties);
  41. return NULL;
  42. }
  43. // First apply the node url properties. Following that,
  44. // apply the normal node properties and create the animations.
  45. // We apply physics properties after all other node properties
  46. // so that the transform (SRT) properties get applied before
  47. // processing physics collision objects.
  48. applyNodeUrls(scene);
  49. applyNodeProperties(scene, sceneProperties,
  50. SceneNodeProperty::AUDIO |
  51. SceneNodeProperty::MATERIAL |
  52. SceneNodeProperty::PARTICLE |
  53. SceneNodeProperty::ROTATE |
  54. SceneNodeProperty::SCALE |
  55. SceneNodeProperty::TRANSLATE |
  56. SceneNodeProperty::TRANSPARENT);
  57. applyNodeProperties(scene, sceneProperties, SceneNodeProperty::CHARACTER | SceneNodeProperty::GHOST | SceneNodeProperty::RIGIDBODY);
  58. createAnimations(scene);
  59. // Find the physics properties object.
  60. Properties* physics = NULL;
  61. Properties* ns = NULL;
  62. sceneProperties->rewind();
  63. while (true)
  64. {
  65. Properties* ns = sceneProperties->getNextNamespace();
  66. if (ns == NULL || strcmp(ns->getNamespace(), "physics") == 0)
  67. {
  68. physics = ns;
  69. break;
  70. }
  71. }
  72. // Load physics properties and constraints.
  73. if (physics)
  74. loadPhysics(physics, scene);
  75. // Clean up all loaded properties objects.
  76. std::map<std::string, Properties*>::iterator iter = _propertiesFromFile.begin();
  77. for (; iter != _propertiesFromFile.end(); iter++)
  78. {
  79. SAFE_DELETE(iter->second);
  80. }
  81. // Clean up the .scene file's properties object.
  82. SAFE_DELETE(properties);
  83. // Clear all temporary data stores.
  84. _propertiesFromFile.clear();
  85. _animations.clear();
  86. _sceneNodes.clear();
  87. return scene;
  88. }
  89. void SceneLoader::addSceneAnimation(const char* animationID, const char* targetID, const char* url)
  90. {
  91. // Calculate the file and id from the given url.
  92. std::string file;
  93. std::string id;
  94. splitURL(url, &file, &id);
  95. // If there is a file that needs to be loaded later, add an
  96. // empty entry to the properties table to signify it.
  97. if (file.length() > 0 && _propertiesFromFile.count(file) == 0)
  98. _propertiesFromFile[file] = NULL;
  99. // Add the animation to the list of animations to be resolved later.
  100. _animations.push_back(SceneAnimation(animationID, targetID, file, id));
  101. }
  102. void SceneLoader::addSceneNodeProperty(SceneNode& sceneNode, SceneNodeProperty::Type type, const char* url, int index)
  103. {
  104. // Calculate the file and id from the given url.
  105. std::string file;
  106. std::string id;
  107. splitURL(url, &file, &id);
  108. // If there is a non-GPB file that needs to be loaded later, add an
  109. // empty entry to the properties table to signify it.
  110. if (file.length() > 0 && file.find(".gpb") == file.npos && _propertiesFromFile.count(file) == 0)
  111. _propertiesFromFile[file] = NULL;
  112. SceneNodeProperty prop(type, file, id, index);
  113. // Parse for wildcharacter character (only supported on the URL attribute)
  114. if (type == SceneNodeProperty::URL)
  115. {
  116. if (id.length() > 1 && id.at(id.length()-1) == '*')
  117. {
  118. prop._id = id.substr(0, id.length()-1);
  119. sceneNode._exactMatch = false;
  120. }
  121. }
  122. // Add the node property to the list of node properties to be resolved later.
  123. sceneNode._properties.push_back(prop);
  124. }
  125. void SceneLoader::applyNodeProperties(const Scene* scene, const Properties* sceneProperties, unsigned int typeFlags)
  126. {
  127. for (unsigned int i = 0, ncount = _sceneNodes.size(); i < ncount; ++i)
  128. {
  129. SceneNode& sceneNode = _sceneNodes[i];
  130. if (sceneNode._exactMatch)
  131. {
  132. // Find the node matching the specified ID exactly
  133. Node* node = scene->findNode(sceneNode._nodeID);
  134. if (!node)
  135. {
  136. WARN_VARG("Attempting to set a property for node '%s', which does not exist in the scene.", sceneNode._nodeID);
  137. continue;
  138. }
  139. for (unsigned int j = 0, pcount = sceneNode._properties.size(); j < pcount; ++j)
  140. {
  141. SceneNodeProperty& snp = sceneNode._properties[j];
  142. if (typeFlags & snp._type)
  143. applyNodeProperty(sceneNode, node, sceneProperties, snp);
  144. }
  145. }
  146. else
  147. {
  148. // Find all nodes matching the specified ID
  149. std::vector<Node*> nodes;
  150. unsigned int nodeCount = scene->findNodes(sceneNode._nodeID, nodes, true, false);
  151. if (nodeCount == 0)
  152. continue;
  153. for (unsigned int j = 0, pcount = sceneNode._properties.size(); j < pcount; ++j)
  154. {
  155. SceneNodeProperty& snp = sceneNode._properties[j];
  156. if ((typeFlags & snp._type) == 0)
  157. continue;
  158. for (unsigned int k = 0; k < nodeCount; ++k)
  159. applyNodeProperty(sceneNode, nodes[k], sceneProperties, snp);
  160. }
  161. }
  162. }
  163. }
  164. void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Properties* sceneProperties, const SceneNodeProperty& snp)
  165. {
  166. if (snp._type == SceneNodeProperty::AUDIO ||
  167. snp._type == SceneNodeProperty::MATERIAL ||
  168. snp._type == SceneNodeProperty::PARTICLE ||
  169. snp._type == SceneNodeProperty::CHARACTER ||
  170. snp._type == SceneNodeProperty::GHOST ||
  171. snp._type == SceneNodeProperty::RIGIDBODY)
  172. {
  173. // Check to make sure the referenced properties object was loaded properly.
  174. Properties* p = _propertiesFromFile[snp._file];
  175. if (!p)
  176. {
  177. WARN_VARG("The referenced node data in file '%s' failed to load.", snp._file.c_str());
  178. return;
  179. }
  180. // If a specific namespace within the file was specified, load that namespace.
  181. if (snp._id.size() > 0)
  182. {
  183. p = p->getNamespace(snp._id.c_str());
  184. if (!p)
  185. {
  186. WARN_VARG("The referenced node data at '%s#%s' failed to load.", snp._file.c_str(), snp._id.c_str());
  187. return;
  188. }
  189. }
  190. else
  191. {
  192. // Otherwise, use the first namespace.
  193. p->rewind();
  194. p = p->getNextNamespace();
  195. }
  196. switch (snp._type)
  197. {
  198. case SceneNodeProperty::AUDIO:
  199. {
  200. AudioSource* audioSource = AudioSource::create(p);
  201. node->setAudioSource(audioSource);
  202. SAFE_RELEASE(audioSource);
  203. break;
  204. }
  205. case SceneNodeProperty::MATERIAL:
  206. if (!node->getModel())
  207. WARN_VARG("Attempting to set a material on node '%s', which has no model.", sceneNode._nodeID);
  208. else
  209. {
  210. Material* material = Material::create(p);
  211. node->getModel()->setMaterial(material, snp._index);
  212. SAFE_RELEASE(material);
  213. }
  214. break;
  215. case SceneNodeProperty::PARTICLE:
  216. {
  217. ParticleEmitter* particleEmitter = ParticleEmitter::create(p);
  218. node->setParticleEmitter(particleEmitter);
  219. SAFE_RELEASE(particleEmitter);
  220. break;
  221. }
  222. case SceneNodeProperty::CHARACTER:
  223. case SceneNodeProperty::GHOST:
  224. case SceneNodeProperty::RIGIDBODY:
  225. {
  226. // Check to make sure the referenced properties object was loaded properly.
  227. Properties* p = _propertiesFromFile[snp._file];
  228. if (!p)
  229. {
  230. WARN_VARG("The referenced node data in file '%s' failed to load.", snp._file.c_str());
  231. return;
  232. }
  233. // If a specific namespace within the file was specified, load that namespace.
  234. if (snp._id.size() > 0)
  235. {
  236. p = p->getNamespace(snp._id.c_str());
  237. if (!p)
  238. {
  239. WARN_VARG("The referenced node data at '%s#%s' failed to load.", snp._file.c_str(), snp._id.c_str());
  240. return;
  241. }
  242. }
  243. else
  244. {
  245. // Otherwise, use the first namespace.
  246. p->rewind();
  247. p = p->getNextNamespace();
  248. }
  249. // Check to make sure the type of the namespace used to load the physics collision object is correct.
  250. if (snp._type == SceneNodeProperty::CHARACTER && strcmp(p->getNamespace(), "character") != 0)
  251. {
  252. WARN_VARG("Attempting to set a 'character' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
  253. }
  254. else if (snp._type == SceneNodeProperty::GHOST && strcmp(p->getNamespace(), "ghost") != 0)
  255. {
  256. WARN_VARG("Attempting to set a 'ghost' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
  257. }
  258. else if (snp._type == SceneNodeProperty::RIGIDBODY && strcmp(p->getNamespace(), "rigidbody") != 0)
  259. {
  260. WARN_VARG("Attempting to set a 'rigidbody' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
  261. }
  262. else
  263. {
  264. // If the scene file specifies a rigid body model, use it for creating the collision object.
  265. Properties* np = sceneProperties->getNamespace(sceneNode._nodeID);
  266. const char* name = NULL;
  267. if (np && (name = np->getString("rigidbodymodel")))
  268. {
  269. Node* modelNode = node->getScene()->findNode(name);
  270. if (!modelNode)
  271. WARN_VARG("Node '%s' does not exist; attempting to use its model for collision object creation.", name);
  272. else
  273. {
  274. if (!modelNode->getModel())
  275. WARN_VARG("Node '%s' does not have a model; attempting to use its model for collision object creation.", name);
  276. else
  277. {
  278. // Temporarily set rigidbody model on model so it's used during collision object creation.
  279. Model* model = node->getModel();
  280. assert(model);
  281. // Up ref count to prevent node from releasing the model when we swap it.
  282. model->addRef();
  283. // Create collision object with new rigidbodymodel set.
  284. node->setModel(modelNode->getModel());
  285. node->setCollisionObject(p);
  286. // Restore original model.
  287. node->setModel(model);
  288. // Decrement temporarily added reference.
  289. model->release();
  290. }
  291. }
  292. }
  293. else
  294. node->setCollisionObject(p);
  295. }
  296. break;
  297. }
  298. default:
  299. // This cannot happen.
  300. break;
  301. }
  302. }
  303. else
  304. {
  305. // Handle Scale, Rotate and Translate
  306. Properties* np = sceneProperties->getNamespace(sceneNode._nodeID);
  307. const char* name = NULL;
  308. switch (snp._type)
  309. {
  310. case SceneNodeProperty::TRANSLATE:
  311. {
  312. Vector3 t;
  313. if (np && np->getVector3("translate", &t))
  314. node->setTranslation(t);
  315. break;
  316. }
  317. case SceneNodeProperty::ROTATE:
  318. {
  319. Quaternion r;
  320. if (np && np->getQuaternionFromAxisAngle("rotate", &r))
  321. node->setRotation(r);
  322. break;
  323. }
  324. case SceneNodeProperty::SCALE:
  325. {
  326. Vector3 s;
  327. if (np && np->getVector3("scale", &s))
  328. node->setScale(s);
  329. break;
  330. }
  331. case SceneNodeProperty::TRANSPARENT:
  332. {
  333. node->setTransparent(true);
  334. break;
  335. }
  336. default:
  337. WARN_VARG("Unsupported node property type: %d.", snp._type);
  338. break;
  339. }
  340. }
  341. }
  342. void SceneLoader::applyNodeUrls(Scene* scene)
  343. {
  344. // Apply all URL node properties so that when we go to apply
  345. // the other node properties, the node is in the scene.
  346. for (unsigned int i = 0, ncount = _sceneNodes.size(); i < ncount; ++i)
  347. {
  348. SceneNode& sceneNode = _sceneNodes[i];
  349. // Iterate backwards over the properties list so we can remove properties as we go
  350. // without danger of indexing out of bounds.
  351. for (int j = sceneNode._properties.size() - 1; j >= 0; --j)
  352. {
  353. SceneNodeProperty& snp = sceneNode._properties[j];
  354. if (snp._type != SceneNodeProperty::URL)
  355. continue;
  356. if (snp._file.empty())
  357. {
  358. // The node is from the main GPB and should just be renamed.
  359. // TODO: Should we do all nodes with this case first to allow users to stitch in nodes with
  360. // IDs equal to IDs that were in the original GPB file but were changed in the scene file?
  361. if (sceneNode._exactMatch)
  362. {
  363. Node* node = scene->findNode(snp._id.c_str());
  364. if (node)
  365. {
  366. node->setId(sceneNode._nodeID);
  367. }
  368. else
  369. {
  370. WARN_VARG("Could not find node '%s' in main scene GPB file.", snp._id.c_str());
  371. }
  372. }
  373. else
  374. {
  375. // Search for nodes using a partial match
  376. std::string partialMatch = snp._id;
  377. std::vector<Node*> nodes;
  378. unsigned int nodeCount = scene->findNodes(snp._id.c_str(), nodes, true, false);
  379. if (nodeCount > 0)
  380. {
  381. for (unsigned int k = 0; k < nodeCount; ++k)
  382. {
  383. // Construct a new node ID using _nodeID plus the remainder of the partial match.
  384. Node* node = nodes[k];
  385. std::string newID(sceneNode._nodeID);
  386. newID += (node->getId() + snp._id.length());
  387. node->setId(newID.c_str());
  388. }
  389. }
  390. else
  391. {
  392. WARN_VARG("Could not find any nodes matching '%s' in main scene GPB file.", snp._id.c_str());
  393. }
  394. }
  395. }
  396. else
  397. {
  398. // An external file was referenced, so load the node from file and then insert it into the scene with the new ID.
  399. // TODO: Revisit this to determine if we should cache Bundle objects for the duration of the scene
  400. // load to prevent constantly creating/destroying the same externally referenced packages each time
  401. // a url with a file is encountered.
  402. Bundle* tmpPackage = Bundle::create(snp._file.c_str());
  403. if (tmpPackage)
  404. {
  405. if (sceneNode._exactMatch)
  406. {
  407. Node* node = tmpPackage->loadNode(snp._id.c_str());
  408. if (node)
  409. {
  410. node->setId(sceneNode._nodeID);
  411. scene->addNode(node);
  412. SAFE_RELEASE(node);
  413. }
  414. else
  415. {
  416. WARN_VARG("Could not load node '%s' in GPB file '%s'.", snp._id.c_str(), snp._file.c_str());
  417. }
  418. }
  419. else
  420. {
  421. // Search for nodes in the bundle using a partial match
  422. std::string partialMatch = snp._id;
  423. unsigned int objectCount = tmpPackage->getObjectCount();
  424. unsigned int matchCount = 0;
  425. for (unsigned int k = 0; k < objectCount; ++k)
  426. {
  427. const char* objid = tmpPackage->getObjectID(k);
  428. if (strstr(objid, snp._id.c_str()) == objid)
  429. {
  430. // This object ID matches (starts with).
  431. // Try to load this object as a Node.
  432. Node* node = tmpPackage->loadNode(objid);
  433. if (node)
  434. {
  435. // Construct a new node ID using _nodeID plus the remainder of the partial match.
  436. std::string newID(sceneNode._nodeID);
  437. newID += (node->getId() + snp._id.length());
  438. node->setId(newID.c_str());
  439. scene->addNode(node);
  440. SAFE_RELEASE(node);
  441. matchCount++;
  442. }
  443. }
  444. }
  445. if (matchCount == 0)
  446. {
  447. WARN_VARG("Could not find any nodes matching '%s' in GPB file '%s'.", snp._id.c_str(), snp._file.c_str());
  448. }
  449. }
  450. SAFE_RELEASE(tmpPackage);
  451. }
  452. else
  453. {
  454. WARN_VARG("Failed to load GPB file '%s' for node stitching.", snp._file.c_str());
  455. }
  456. }
  457. // Remove the node property since we are done applying it.
  458. sceneNode._properties.erase(sceneNode._properties.begin() + j);
  459. }
  460. }
  461. }
  462. void SceneLoader::buildReferenceTables(Properties* sceneProperties)
  463. {
  464. // Go through the child namespaces of the scene.
  465. Properties* ns;
  466. const char* name = NULL;
  467. while ((ns = sceneProperties->getNextNamespace()) != NULL)
  468. {
  469. if (strcmp(ns->getNamespace(), "node") == 0)
  470. {
  471. if (strlen(ns->getId()) == 0)
  472. {
  473. WARN("Nodes must have an ID; skipping the current node.");
  474. continue;
  475. }
  476. // Add a SceneNode to the end of the list
  477. _sceneNodes.resize(_sceneNodes.size() + 1);
  478. SceneNode& sceneNode = _sceneNodes[_sceneNodes.size()-1];
  479. sceneNode._nodeID = ns->getId();
  480. while ((name = ns->getNextProperty()) != NULL)
  481. {
  482. if (strcmp(name, "url") == 0)
  483. {
  484. addSceneNodeProperty(sceneNode, SceneNodeProperty::URL, ns->getString());
  485. }
  486. else if (strcmp(name, "audio") == 0)
  487. {
  488. addSceneNodeProperty(sceneNode, SceneNodeProperty::AUDIO, ns->getString());
  489. }
  490. else if (strncmp(name, "material", 8) == 0)
  491. {
  492. int materialIndex = -1;
  493. name = strchr(name, '[');
  494. if (name && strlen(name) >= 3)
  495. {
  496. std::string indexString(name);
  497. indexString = indexString.substr(1, indexString.size()-2);
  498. materialIndex = (unsigned int)atoi(indexString.c_str());
  499. }
  500. addSceneNodeProperty(sceneNode, SceneNodeProperty::MATERIAL, ns->getString(), materialIndex);
  501. }
  502. else if (strcmp(name, "particle") == 0)
  503. {
  504. addSceneNodeProperty(sceneNode, SceneNodeProperty::PARTICLE, ns->getString());
  505. }
  506. else if (strcmp(name, "character") == 0)
  507. {
  508. addSceneNodeProperty(sceneNode, SceneNodeProperty::CHARACTER, ns->getString());
  509. }
  510. else if (strcmp(name, "ghost") == 0)
  511. {
  512. addSceneNodeProperty(sceneNode, SceneNodeProperty::GHOST, ns->getString());
  513. }
  514. else if (strcmp(name, "rigidbody") == 0)
  515. {
  516. addSceneNodeProperty(sceneNode, SceneNodeProperty::RIGIDBODY, ns->getString());
  517. }
  518. else if (strcmp(name, "rigidbodymodel") == 0)
  519. {
  520. // Ignore this for now. We process this when we do rigid body creation.
  521. }
  522. else if (strcmp(name, "translate") == 0)
  523. {
  524. addSceneNodeProperty(sceneNode, SceneNodeProperty::TRANSLATE);
  525. }
  526. else if (strcmp(name, "rotate") == 0)
  527. {
  528. addSceneNodeProperty(sceneNode, SceneNodeProperty::ROTATE);
  529. }
  530. else if (strcmp(name, "scale") == 0)
  531. {
  532. addSceneNodeProperty(sceneNode, SceneNodeProperty::SCALE);
  533. }
  534. else if (strcmp(name, "transparent") == 0)
  535. {
  536. addSceneNodeProperty(sceneNode, SceneNodeProperty::TRANSPARENT);
  537. }
  538. else
  539. {
  540. WARN_VARG("Unsupported node property: %s = %s", name, ns->getString());
  541. }
  542. }
  543. }
  544. else if (strcmp(ns->getNamespace(), "animations") == 0)
  545. {
  546. // Load all the animations.
  547. Properties* animation;
  548. while ((animation = ns->getNextNamespace()) != NULL)
  549. {
  550. if (strcmp(animation->getNamespace(), "animation") == 0)
  551. {
  552. const char* animationID = animation->getId();
  553. if (strlen(animationID) == 0)
  554. {
  555. WARN("Animations must have an ID; skipping the current animation.");
  556. continue;
  557. }
  558. const char* url = animation->getString("url");
  559. if (!url)
  560. {
  561. WARN_VARG("Animations must have a URL; skipping animation '%s'.", animationID);
  562. continue;
  563. }
  564. const char* targetID = animation->getString("target");
  565. if (!targetID)
  566. {
  567. WARN_VARG("Animations must have a target; skipping animation '%s'.", animationID);
  568. continue;
  569. }
  570. addSceneAnimation(animationID, targetID, url);
  571. }
  572. else
  573. {
  574. WARN_VARG("Unsupported child namespace (of 'animations'): %s", ns->getNamespace());
  575. }
  576. }
  577. }
  578. else if (strcmp(ns->getNamespace(), "physics") == 0)
  579. {
  580. // Note: we don't load physics until the whole scene file has been
  581. // loaded so that all node references (i.e. for constraints) can be resolved.
  582. }
  583. else
  584. {
  585. // TODO: Should we ignore these items? They could be used for generic properties file inheritence.
  586. WARN_VARG("Unsupported child namespace (of 'scene'): %s", ns->getNamespace());
  587. }
  588. }
  589. }
  590. void SceneLoader::createAnimations(const Scene* scene)
  591. {
  592. // Create the scene animations.
  593. for (unsigned int i = 0, count = _animations.size(); i < count; i++)
  594. {
  595. // If the target node doesn't exist in the scene, then we
  596. // can't do anything so we skip to the next animation.
  597. Node* node = scene->findNode(_animations[i]._targetID);
  598. if (!node)
  599. {
  600. WARN_VARG("Attempting to create an animation targeting node '%s', which does not exist in the scene.", _animations[i]._targetID);
  601. continue;
  602. }
  603. // Check to make sure the referenced properties object was loaded properly.
  604. Properties* p = _propertiesFromFile[_animations[i]._file];
  605. if (!p)
  606. {
  607. WARN_VARG("The referenced animation data in file '%s' failed to load.", _animations[i]._file.c_str());
  608. continue;
  609. }
  610. if (_animations[i]._id.size() > 0)
  611. {
  612. p = p->getNamespace(_animations[i]._id.c_str());
  613. if (!p)
  614. {
  615. WARN_VARG("The referenced animation data at '%s#%s' failed to load.", _animations[i]._file.c_str(), _animations[i]._id.c_str());
  616. continue;
  617. }
  618. }
  619. node->createAnimation(_animations[i]._animationID, p);
  620. }
  621. }
  622. PhysicsConstraint* SceneLoader::loadGenericConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
  623. {
  624. PhysicsGenericConstraint* physicsConstraint;
  625. // Create the constraint from the specified properties.
  626. Quaternion roA;
  627. Vector3 toA;
  628. bool offsetSpecified = constraint->getQuaternionFromAxisAngle("rotationOffsetA", &roA);
  629. offsetSpecified |= constraint->getVector3("translationOffsetA", &toA);
  630. if (offsetSpecified)
  631. {
  632. if (rbB)
  633. {
  634. Quaternion roB;
  635. Vector3 toB;
  636. constraint->getQuaternionFromAxisAngle("rotationOffsetB", &roB);
  637. constraint->getVector3("translationOffsetB", &toB);
  638. physicsConstraint = Game::getInstance()->getPhysicsController()->createGenericConstraint(rbA, roA, toB, rbB, roB, toB);
  639. }
  640. else
  641. {
  642. physicsConstraint = Game::getInstance()->getPhysicsController()->createGenericConstraint(rbA, roA, toA);
  643. }
  644. }
  645. else
  646. {
  647. physicsConstraint = Game::getInstance()->getPhysicsController()->createGenericConstraint(rbA, rbB);
  648. }
  649. // Set the optional parameters that were specified.
  650. Vector3 v;
  651. if (constraint->getVector3("angularLowerLimit", &v))
  652. physicsConstraint->setAngularLowerLimit(v);
  653. if (constraint->getVector3("angularUpperLimit", &v))
  654. physicsConstraint->setAngularUpperLimit(v);
  655. if (constraint->getVector3("linearLowerLimit", &v))
  656. physicsConstraint->setLinearLowerLimit(v);
  657. if (constraint->getVector3("linearUpperLimit", &v))
  658. physicsConstraint->setLinearUpperLimit(v);
  659. return physicsConstraint;
  660. }
  661. PhysicsConstraint* SceneLoader::loadHingeConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
  662. {
  663. PhysicsHingeConstraint* physicsConstraint = NULL;
  664. // Create the constraint from the specified properties.
  665. Quaternion roA;
  666. Vector3 toA;
  667. constraint->getQuaternionFromAxisAngle("rotationOffsetA", &roA);
  668. constraint->getVector3("translationOffsetA", &toA);
  669. if (rbB)
  670. {
  671. Quaternion roB;
  672. Vector3 toB;
  673. constraint->getQuaternionFromAxisAngle("rotationOffsetB", &roB);
  674. constraint->getVector3("translationOffsetB", &toB);
  675. physicsConstraint = Game::getInstance()->getPhysicsController()->createHingeConstraint(rbA, roA, toB, rbB, roB, toB);
  676. }
  677. else
  678. {
  679. physicsConstraint = Game::getInstance()->getPhysicsController()->createHingeConstraint(rbA, roA, toA);
  680. }
  681. // Attempt to load the hinge limits first as a Vector3 and if that doesn't work, try loading as a Vector2.
  682. // We do this because the user can specify just the min and max angle, or both angle along with bounciness.
  683. Vector3 fullLimits;
  684. Vector2 angleLimits;
  685. if (constraint->getVector3("limits", &fullLimits))
  686. physicsConstraint->setLimits(MATH_DEG_TO_RAD(fullLimits.x), MATH_DEG_TO_RAD(fullLimits.y), fullLimits.z);
  687. else if (constraint->getVector2("limits", &angleLimits))
  688. physicsConstraint->setLimits(angleLimits.x, angleLimits.y);
  689. return physicsConstraint;
  690. }
  691. Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
  692. {
  693. // Load the main scene from the specified path.
  694. Bundle* bundle = Bundle::create(_path.c_str());
  695. if (!bundle)
  696. {
  697. WARN_VARG("Failed to load scene GPB file '%s'.", _path.c_str());
  698. return NULL;
  699. }
  700. const char* sceneID = strlen(sceneProperties->getId()) == 0 ? NULL : sceneProperties->getId();
  701. Scene* scene = bundle->loadScene(sceneID);
  702. if (!scene)
  703. {
  704. WARN_VARG("Failed to load scene from '%s'.", _path.c_str());
  705. SAFE_RELEASE(bundle);
  706. return NULL;
  707. }
  708. // Go through the supported scene properties and apply them to the scene.
  709. const char* name = sceneProperties->getString("activeCamera");
  710. if (name)
  711. {
  712. Node* camera = scene->findNode(name);
  713. if (camera && camera->getCamera())
  714. scene->setActiveCamera(camera->getCamera());
  715. }
  716. SAFE_RELEASE(bundle);
  717. return scene;
  718. }
  719. void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
  720. {
  721. // Go through the supported global physics properties and apply them.
  722. Vector3 gravity;
  723. if (physics->getVector3("gravity", &gravity))
  724. Game::getInstance()->getPhysicsController()->setGravity(gravity);
  725. Properties* constraint;
  726. const char* name;
  727. while ((constraint = physics->getNextNamespace()) != NULL)
  728. {
  729. if (strcmp(constraint->getNamespace(), "constraint") == 0)
  730. {
  731. // Get the constraint type.
  732. std::string type = constraint->getString("type");
  733. // Attempt to load the first rigid body. If the first rigid body cannot
  734. // be loaded or found, then continue to the next constraint (error).
  735. name = constraint->getString("rigidBodyA");
  736. if (!name)
  737. {
  738. WARN_VARG("Missing property 'rigidBodyA' for constraint %s", constraint->getId());
  739. continue;
  740. }
  741. Node* rbANode = scene->findNode(name);
  742. if (!rbANode)
  743. {
  744. WARN_VARG("Node '%s' to be used as 'rigidBodyA' for constraint %s cannot be found.", name, constraint->getId());
  745. continue;
  746. }
  747. if (!rbANode->getCollisionObject() || rbANode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
  748. {
  749. WARN_VARG("Node '%s' to be used as 'rigidBodyA' does not have a rigid body.", name);
  750. continue;
  751. }
  752. PhysicsRigidBody* rbA = static_cast<PhysicsRigidBody*>(rbANode->getCollisionObject());
  753. // Attempt to load the second rigid body. If the second rigid body is not
  754. // specified, that is usually okay (only spring constraints require both and
  755. // we check that below), but if the second rigid body is specified and it doesn't
  756. // load properly, then continue to the next constraint (error).
  757. name = constraint->getString("rigidBodyB");
  758. PhysicsRigidBody* rbB = NULL;
  759. if (name)
  760. {
  761. Node* rbBNode = scene->findNode(name);
  762. if (!rbBNode)
  763. {
  764. WARN_VARG("Node '%s' to be used as 'rigidBodyB' for constraint %s cannot be found.", name, constraint->getId());
  765. continue;
  766. }
  767. if (!rbBNode->getCollisionObject() || rbBNode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
  768. {
  769. WARN_VARG("Node '%s' to be used as 'rigidBodyB' does not have a rigid body.", name);
  770. continue;
  771. }
  772. rbB = static_cast<PhysicsRigidBody*>(rbBNode->getCollisionObject());
  773. }
  774. PhysicsConstraint* physicsConstraint = NULL;
  775. // Load the constraint based on its type.
  776. if (type == "FIXED")
  777. {
  778. physicsConstraint = Game::getInstance()->getPhysicsController()->createFixedConstraint(rbA, rbB);
  779. }
  780. else if (type == "GENERIC")
  781. {
  782. physicsConstraint = loadGenericConstraint(constraint, rbA, rbB);
  783. }
  784. else if (type == "HINGE")
  785. {
  786. physicsConstraint = loadHingeConstraint(constraint, rbA, rbB);
  787. }
  788. else if (type == "SOCKET")
  789. {
  790. physicsConstraint = loadSocketConstraint(constraint, rbA, rbB);
  791. }
  792. else if (type == "SPRING")
  793. {
  794. physicsConstraint = loadSpringConstraint(constraint, rbA, rbB);
  795. }
  796. // If the constraint failed to load, continue on to the next one.
  797. if (!physicsConstraint)
  798. continue;
  799. // If the breaking impulse was specified, apply it to the constraint.
  800. if (constraint->getString("breakingImpulse"))
  801. physicsConstraint->setBreakingImpulse(constraint->getFloat("breakingImpulse"));
  802. }
  803. else
  804. {
  805. WARN_VARG("Unsupported child namespace (of 'physics'): %s", physics->getNamespace());
  806. }
  807. }
  808. }
  809. void SceneLoader::loadReferencedFiles()
  810. {
  811. // Load all referenced properties files.
  812. std::map<std::string, Properties*>::iterator iter = _propertiesFromFile.begin();
  813. for (; iter != _propertiesFromFile.end(); iter++)
  814. {
  815. Properties* p = Properties::create(iter->first.c_str());
  816. assert(p);
  817. if (p == NULL)
  818. WARN_VARG("Failed to load referenced file: %s", iter->first.c_str());
  819. iter->second = p;
  820. }
  821. }
  822. PhysicsConstraint* SceneLoader::loadSocketConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
  823. {
  824. PhysicsSocketConstraint* physicsConstraint = NULL;
  825. Vector3 toA;
  826. bool offsetSpecified = constraint->getVector3("translationOffsetA", &toA);
  827. if (offsetSpecified)
  828. {
  829. if (rbB)
  830. {
  831. Vector3 toB;
  832. constraint->getVector3("translationOffsetB", &toB);
  833. physicsConstraint = Game::getInstance()->getPhysicsController()->createSocketConstraint(rbA, toA, rbB, toB);
  834. }
  835. else
  836. {
  837. physicsConstraint = Game::getInstance()->getPhysicsController()->createSocketConstraint(rbA, toA);
  838. }
  839. }
  840. else
  841. {
  842. physicsConstraint = Game::getInstance()->getPhysicsController()->createSocketConstraint(rbA, rbB);
  843. }
  844. return physicsConstraint;
  845. }
  846. PhysicsConstraint* SceneLoader::loadSpringConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
  847. {
  848. if (!rbB)
  849. {
  850. WARN("Spring constraints require two rigid bodies.");
  851. return NULL;
  852. }
  853. PhysicsSpringConstraint* physicsConstraint = NULL;
  854. // Create the constraint from the specified properties.
  855. Quaternion roA, roB;
  856. Vector3 toA, toB;
  857. bool offsetsSpecified = constraint->getQuaternionFromAxisAngle("rotationOffsetA", &roA);
  858. offsetsSpecified |= constraint->getVector3("translationOffsetA", &toA);
  859. offsetsSpecified |= constraint->getQuaternionFromAxisAngle("rotationOffsetB", &roB);
  860. offsetsSpecified |= constraint->getVector3("translationOffsetB", &toB);
  861. if (offsetsSpecified)
  862. {
  863. physicsConstraint = Game::getInstance()->getPhysicsController()->createSpringConstraint(rbA, roA, toB, rbB, roB, toB);
  864. }
  865. else
  866. {
  867. physicsConstraint = Game::getInstance()->getPhysicsController()->createSpringConstraint(rbA, rbB);
  868. }
  869. // Set the optional parameters that were specified.
  870. Vector3 v;
  871. if (constraint->getVector3("angularLowerLimit", &v))
  872. physicsConstraint->setAngularLowerLimit(v);
  873. if (constraint->getVector3("angularUpperLimit", &v))
  874. physicsConstraint->setAngularUpperLimit(v);
  875. if (constraint->getVector3("linearLowerLimit", &v))
  876. physicsConstraint->setLinearLowerLimit(v);
  877. if (constraint->getVector3("linearUpperLimit", &v))
  878. physicsConstraint->setLinearUpperLimit(v);
  879. if (constraint->getString("angularDampingX"))
  880. physicsConstraint->setAngularDampingX(constraint->getFloat("angularDampingX"));
  881. if (constraint->getString("angularDampingY"))
  882. physicsConstraint->setAngularDampingY(constraint->getFloat("angularDampingY"));
  883. if (constraint->getString("angularDampingZ"))
  884. physicsConstraint->setAngularDampingZ(constraint->getFloat("angularDampingZ"));
  885. if (constraint->getString("angularStrengthX"))
  886. physicsConstraint->setAngularStrengthX(constraint->getFloat("angularStrengthX"));
  887. if (constraint->getString("angularStrengthY"))
  888. physicsConstraint->setAngularStrengthY(constraint->getFloat("angularStrengthY"));
  889. if (constraint->getString("angularStrengthZ"))
  890. physicsConstraint->setAngularStrengthZ(constraint->getFloat("angularStrengthZ"));
  891. if (constraint->getString("linearDampingX"))
  892. physicsConstraint->setLinearDampingX(constraint->getFloat("linearDampingX"));
  893. if (constraint->getString("linearDampingY"))
  894. physicsConstraint->setLinearDampingY(constraint->getFloat("linearDampingY"));
  895. if (constraint->getString("linearDampingZ"))
  896. physicsConstraint->setLinearDampingZ(constraint->getFloat("linearDampingZ"));
  897. if (constraint->getString("linearStrengthX"))
  898. physicsConstraint->setLinearStrengthX(constraint->getFloat("linearStrengthX"));
  899. if (constraint->getString("linearStrengthY"))
  900. physicsConstraint->setLinearStrengthY(constraint->getFloat("linearStrengthY"));
  901. if (constraint->getString("linearStrengthZ"))
  902. physicsConstraint->setLinearStrengthZ(constraint->getFloat("linearStrengthZ"));
  903. return physicsConstraint;
  904. }
  905. void SceneLoader::splitURL(const char* url, std::string* file, std::string* id)
  906. {
  907. if (!url)
  908. return;
  909. std::string urlString = url;
  910. // Check if the url references a file (otherwise, it only references a node within the main GPB).
  911. unsigned int loc = urlString.rfind(".");
  912. if (loc != urlString.npos)
  913. {
  914. // If the url references a specific namespace within the file,
  915. // set the id out parameter appropriately. Otherwise, set the id out
  916. // parameter to the empty string so we know to load the first namespace.
  917. loc = urlString.rfind("#");
  918. if (loc != urlString.npos)
  919. {
  920. *file = urlString.substr(0, loc);
  921. *id = urlString.substr(loc + 1);
  922. }
  923. else
  924. {
  925. *file = url;
  926. *id = std::string();
  927. }
  928. }
  929. else
  930. {
  931. *file = std::string();
  932. *id = url;
  933. }
  934. }
  935. }