SceneLoader.cpp 46 KB

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