SceneLoader.cpp 46 KB

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