SceneLoader.cpp 37 KB

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