SceneLoader.cpp 43 KB

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