LevelLoader.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. // ----------------------------------------------------------------
  2. // From Game Programming in C++ by Sanjay Madhav
  3. // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
  4. //
  5. // Released under the BSD License
  6. // See LICENSE.txt for full details.
  7. // ----------------------------------------------------------------
  8. #include "LevelLoader.h"
  9. #include <fstream>
  10. #include <vector>
  11. #include <SDL/SDL.h>
  12. #include "Game.h"
  13. #include "Renderer.h"
  14. #include "Actor.h"
  15. #include "BallActor.h"
  16. #include "FollowActor.h"
  17. #include "PlaneActor.h"
  18. #include "TargetActor.h"
  19. #include "Component.h"
  20. #include "AudioComponent.h"
  21. #include "BallMove.h"
  22. #include "BoxComponent.h"
  23. #include "CameraComponent.h"
  24. #include "FollowCamera.h"
  25. #include "MeshComponent.h"
  26. #include "MoveComponent.h"
  27. #include "SkeletalMeshComponent.h"
  28. #include "SpriteComponent.h"
  29. #include "MirrorCamera.h"
  30. #include "PointLightComponent.h"
  31. #include "TargetComponent.h"
  32. #include <rapidjson/stringbuffer.h>
  33. #include <rapidjson/prettywriter.h>
  34. const int LevelVersion = 1;
  35. // Declare map of actors to spawn functions
  36. std::unordered_map<std::string, ActorFunc> LevelLoader::sActorFactoryMap
  37. {
  38. { "Actor", &Actor::Create<Actor> },
  39. { "BallActor", &Actor::Create<BallActor> },
  40. { "FollowActor", &Actor::Create<FollowActor> },
  41. { "PlaneActor", &Actor::Create<PlaneActor> },
  42. { "TargetActor", &Actor::Create<TargetActor> },
  43. };
  44. std::unordered_map<std::string, std::pair<int, ComponentFunc>> LevelLoader::sComponentFactoryMap
  45. {
  46. { "AudioComponent", { Component::TAudioComponent, &Component::Create<AudioComponent>} },
  47. { "BallMove", { Component::TBallMove, &Component::Create<BallMove> } },
  48. { "BoxComponent", { Component::TBoxComponent, &Component::Create<BoxComponent> } },
  49. { "CameraComponent", { Component::TCameraComponent, &Component::Create<CameraComponent> } },
  50. { "FollowCamera", { Component::TFollowCamera, &Component::Create<FollowCamera> } },
  51. { "MeshComponent", { Component::TMeshComponent, &Component::Create<MeshComponent> } },
  52. { "MoveComponent", { Component::TMoveComponent, &Component::Create<MoveComponent> } },
  53. { "SkeletalMeshComponent", { Component::TSkeletalMeshComponent, &Component::Create<SkeletalMeshComponent> } },
  54. { "SpriteComponent", { Component::TSpriteComponent, &Component::Create<SpriteComponent> } },
  55. { "MirrorCamera", { Component::TMirrorCamera, &Component::Create<MirrorCamera> } },
  56. { "PointLightComponent", { Component::TPointLightComponent, &Component::Create<PointLightComponent> }},
  57. { "TargetComponent",{ Component::TTargetComponent, &Component::Create<TargetComponent> } },
  58. };
  59. bool LevelLoader::LoadLevel(Game* game, const std::string& fileName)
  60. {
  61. rapidjson::Document doc;
  62. if (!LoadJSON(fileName, doc))
  63. {
  64. SDL_Log("Failed to load level %s", fileName.c_str());
  65. return false;
  66. }
  67. int version = 0;
  68. if (!JsonHelper::GetInt(doc, "version", version) ||
  69. version != LevelVersion)
  70. {
  71. SDL_Log("Incorrect level file version for %s", fileName.c_str());
  72. return false;
  73. }
  74. // Handle any global properties
  75. const rapidjson::Value& globals = doc["globalProperties"];
  76. if (globals.IsObject())
  77. {
  78. LoadGlobalProperties(game, globals);
  79. }
  80. // Handle any actors
  81. const rapidjson::Value& actors = doc["actors"];
  82. if (actors.IsArray())
  83. {
  84. LoadActors(game, actors);
  85. }
  86. return true;
  87. }
  88. bool LevelLoader::LoadJSON(const std::string& fileName, rapidjson::Document& outDoc)
  89. {
  90. // Load the file from disk into an ifstream in binary mode,
  91. // loaded with stream buffer at the end (ate)
  92. std::ifstream file(fileName, std::ios::in | std::ios::binary | std::ios::ate);
  93. if (!file.is_open())
  94. {
  95. SDL_Log("File %s not found", fileName.c_str());
  96. return false;
  97. }
  98. // Get the current position in stream buffer, which is size of file
  99. std::ifstream::pos_type fileSize = file.tellg();
  100. // Seek back to start of file
  101. file.seekg(0, std::ios::beg);
  102. // Create a vector of size + 1 (for null terminator)
  103. std::vector<char> bytes(static_cast<size_t>(fileSize) + 1);
  104. // Read in bytes into vector
  105. file.read(bytes.data(), static_cast<size_t>(fileSize));
  106. // Load raw data into RapidJSON document
  107. outDoc.Parse(bytes.data());
  108. if (!outDoc.IsObject())
  109. {
  110. SDL_Log("File %s is not valid JSON", fileName.c_str());
  111. return false;
  112. }
  113. return true;
  114. }
  115. void LevelLoader::SaveLevel(Game* game, const std::string& fileName)
  116. {
  117. // Create the document and root object
  118. rapidjson::Document doc;
  119. doc.SetObject();
  120. // Write the version
  121. JsonHelper::AddInt(doc.GetAllocator(), doc, "version", LevelVersion);
  122. // Globals
  123. rapidjson::Value globals(rapidjson::kObjectType);
  124. SaveGlobalProperties(doc.GetAllocator(), game, globals);
  125. doc.AddMember("globalProperties", globals, doc.GetAllocator());
  126. // Actors
  127. rapidjson::Value actors(rapidjson::kArrayType);
  128. SaveActors(doc.GetAllocator(), game, actors);
  129. doc.AddMember("actors", actors, doc.GetAllocator());
  130. // Save JSON to string buffer
  131. rapidjson::StringBuffer buffer;
  132. // Use PrettyWriter for pretty output (otherwise use Writer)
  133. rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
  134. doc.Accept(writer);
  135. const char* output = buffer.GetString();
  136. // Write output to file
  137. std::ofstream outFile(fileName);
  138. if (outFile.is_open())
  139. {
  140. outFile << output;
  141. }
  142. }
  143. void LevelLoader::LoadGlobalProperties(Game* game, const rapidjson::Value& inObject)
  144. {
  145. // Get ambient light
  146. Vector3 ambient;
  147. if (JsonHelper::GetVector3(inObject, "ambientLight", ambient))
  148. {
  149. game->GetRenderer()->SetAmbientLight(ambient);
  150. }
  151. // Get directional light
  152. const rapidjson::Value& dirObj = inObject["directionalLight"];
  153. if (dirObj.IsObject())
  154. {
  155. DirectionalLight& light = game->GetRenderer()->GetDirectionalLight();
  156. // Set direction/color, if they exist
  157. JsonHelper::GetVector3(dirObj, "direction", light.mDirection);
  158. JsonHelper::GetVector3(dirObj, "color", light.mDiffuseColor);
  159. }
  160. }
  161. void LevelLoader::LoadActors(Game* game, const rapidjson::Value& inArray)
  162. {
  163. // Loop through array of actors
  164. for (rapidjson::SizeType i = 0; i < inArray.Size(); i++)
  165. {
  166. const rapidjson::Value& actorObj = inArray[i];
  167. if (actorObj.IsObject())
  168. {
  169. // Get the type
  170. std::string type;
  171. if (JsonHelper::GetString(actorObj, "type", type))
  172. {
  173. // Is this type in the map?
  174. auto iter = sActorFactoryMap.find(type);
  175. if (iter != sActorFactoryMap.end())
  176. {
  177. // Construct with function stored in map
  178. Actor* actor = iter->second(game, actorObj["properties"]);
  179. // Get the actor's components
  180. if (actorObj.HasMember("components"))
  181. {
  182. const rapidjson::Value& components = actorObj["components"];
  183. if (components.IsArray())
  184. {
  185. LoadComponents(actor, components);
  186. }
  187. }
  188. }
  189. else
  190. {
  191. SDL_Log("Unknown actor type %s", type.c_str());
  192. }
  193. }
  194. }
  195. }
  196. }
  197. void LevelLoader::LoadComponents(Actor* actor, const rapidjson::Value& inArray)
  198. {
  199. // Loop through array of components
  200. for (rapidjson::SizeType i = 0; i < inArray.Size(); i++)
  201. {
  202. const rapidjson::Value& compObj = inArray[i];
  203. if (compObj.IsObject())
  204. {
  205. // Get the type
  206. std::string type;
  207. if (JsonHelper::GetString(compObj, "type", type))
  208. {
  209. auto iter = sComponentFactoryMap.find(type);
  210. if (iter != sComponentFactoryMap.end())
  211. {
  212. // Get the typeid of component
  213. Component::TypeID tid = static_cast<Component::TypeID>(iter->second.first);
  214. // Does the actor already have a component of this type?
  215. Component* comp = actor->GetComponentOfType(tid);
  216. if (comp == nullptr)
  217. {
  218. // It's a new component, call function from map
  219. comp = iter->second.second(actor, compObj["properties"]);
  220. }
  221. else
  222. {
  223. // It already exists, just load properties
  224. comp->LoadProperties(compObj["properties"]);
  225. }
  226. }
  227. else
  228. {
  229. SDL_Log("Unknown component type %s", type.c_str());
  230. }
  231. }
  232. }
  233. }
  234. }
  235. void LevelLoader::SaveGlobalProperties(rapidjson::Document::AllocatorType& alloc,
  236. Game* game, rapidjson::Value& inObject)
  237. {
  238. // Ambient light
  239. JsonHelper::AddVector3(alloc, inObject, "ambientLight",
  240. game->GetRenderer()->GetAmbientLight());
  241. // Directional light
  242. DirectionalLight& dirLight = game->GetRenderer()->GetDirectionalLight();
  243. rapidjson::Value dirObj(rapidjson::kObjectType);
  244. JsonHelper::AddVector3(alloc, dirObj, "direction", dirLight.mDirection);
  245. JsonHelper::AddVector3(alloc, dirObj, "color", dirLight.mDiffuseColor);
  246. inObject.AddMember("directionalLight", dirObj, alloc);
  247. }
  248. void LevelLoader::SaveActors(rapidjson::Document::AllocatorType& alloc,
  249. Game* game, rapidjson::Value& inArray)
  250. {
  251. const auto& actors = game->GetActors();
  252. for (const Actor* actor : actors)
  253. {
  254. // Make a JSON object
  255. rapidjson::Value obj(rapidjson::kObjectType);
  256. // Add type
  257. JsonHelper::AddString(alloc, obj, "type", Actor::TypeNames[actor->GetType()]);
  258. // Make object for properties
  259. rapidjson::Value props(rapidjson::kObjectType);
  260. // Save properties
  261. actor->SaveProperties(alloc, props);
  262. // Add the properties member
  263. obj.AddMember("properties", props, alloc);
  264. // Save components
  265. rapidjson::Value components(rapidjson::kArrayType);
  266. SaveComponents(alloc, actor, components);
  267. obj.AddMember("components", components, alloc);
  268. // Add actor to inArray
  269. inArray.PushBack(obj, alloc);
  270. }
  271. }
  272. void LevelLoader::SaveComponents(rapidjson::Document::AllocatorType& alloc,
  273. const Actor* actor, rapidjson::Value& inArray)
  274. {
  275. const auto& components = actor->GetComponents();
  276. for (const Component* comp : components)
  277. {
  278. // Make a JSON object
  279. rapidjson::Value obj(rapidjson::kObjectType);
  280. // Add type
  281. JsonHelper::AddString(alloc, obj, "type", Component::TypeNames[comp->GetType()]);
  282. // Make an object for properties
  283. rapidjson::Value props(rapidjson::kObjectType);
  284. // Save rest of properties
  285. comp->SaveProperties(alloc, props);
  286. // Add the member
  287. obj.AddMember("properties", props, alloc);
  288. // Add component to array
  289. inArray.PushBack(obj, alloc);
  290. }
  291. }
  292. bool JsonHelper::GetInt(const rapidjson::Value& inObject, const char* inProperty, int& outInt)
  293. {
  294. // Check if this property exists
  295. auto itr = inObject.FindMember(inProperty);
  296. if (itr == inObject.MemberEnd())
  297. {
  298. return false;
  299. }
  300. // Get the value type, and check it's an integer
  301. auto& property = itr->value;
  302. if (!property.IsInt())
  303. {
  304. return false;
  305. }
  306. // We have the property
  307. outInt = property.GetInt();
  308. return true;
  309. }
  310. bool JsonHelper::GetFloat(const rapidjson::Value& inObject, const char* inProperty, float& outFloat)
  311. {
  312. auto itr = inObject.FindMember(inProperty);
  313. if (itr == inObject.MemberEnd())
  314. {
  315. return false;
  316. }
  317. auto& property = itr->value;
  318. if (!property.IsDouble())
  319. {
  320. return false;
  321. }
  322. outFloat = property.GetDouble();
  323. return true;
  324. }
  325. bool JsonHelper::GetString(const rapidjson::Value& inObject, const char* inProperty, std::string& outStr)
  326. {
  327. auto itr = inObject.FindMember(inProperty);
  328. if (itr == inObject.MemberEnd())
  329. {
  330. return false;
  331. }
  332. auto& property = itr->value;
  333. if (!property.IsString())
  334. {
  335. return false;
  336. }
  337. outStr = property.GetString();
  338. return true;
  339. }
  340. bool JsonHelper::GetBool(const rapidjson::Value& inObject, const char* inProperty, bool& outBool)
  341. {
  342. auto itr = inObject.FindMember(inProperty);
  343. if (itr == inObject.MemberEnd())
  344. {
  345. return false;
  346. }
  347. auto& property = itr->value;
  348. if (!property.IsBool())
  349. {
  350. return false;
  351. }
  352. outBool = property.GetBool();
  353. return true;
  354. }
  355. bool JsonHelper::GetVector3(const rapidjson::Value& inObject, const char* inProperty, Vector3& outVector)
  356. {
  357. auto itr = inObject.FindMember(inProperty);
  358. if (itr == inObject.MemberEnd())
  359. {
  360. return false;
  361. }
  362. auto& property = itr->value;
  363. if (!property.IsArray() || property.Size() != 3)
  364. {
  365. return false;
  366. }
  367. for (rapidjson::SizeType i = 0; i < 3; i++)
  368. {
  369. if (!property[i].IsDouble())
  370. {
  371. return false;
  372. }
  373. }
  374. outVector.x = property[0].GetDouble();
  375. outVector.y = property[1].GetDouble();
  376. outVector.z = property[2].GetDouble();
  377. return true;
  378. }
  379. bool JsonHelper::GetQuaternion(const rapidjson::Value& inObject, const char* inProperty, Quaternion& outQuat)
  380. {
  381. auto itr = inObject.FindMember(inProperty);
  382. if (itr == inObject.MemberEnd())
  383. {
  384. return false;
  385. }
  386. auto& property = itr->value;
  387. for (rapidjson::SizeType i = 0; i < 4; i++)
  388. {
  389. if (!property[i].IsDouble())
  390. {
  391. return false;
  392. }
  393. }
  394. outQuat.x = property[0].GetDouble();
  395. outQuat.y = property[1].GetDouble();
  396. outQuat.z = property[2].GetDouble();
  397. outQuat.w = property[3].GetDouble();
  398. return true;
  399. }
  400. void JsonHelper::AddInt(rapidjson::Document::AllocatorType& alloc,
  401. rapidjson::Value& inObject, const char* name, int value)
  402. {
  403. rapidjson::Value v(value);
  404. inObject.AddMember(rapidjson::StringRef(name), v, alloc);
  405. }
  406. void JsonHelper::AddFloat(rapidjson::Document::AllocatorType& alloc,
  407. rapidjson::Value& inObject, const char* name, float value)
  408. {
  409. rapidjson::Value v(value);
  410. inObject.AddMember(rapidjson::StringRef(name), v, alloc);
  411. }
  412. void JsonHelper::AddString(rapidjson::Document::AllocatorType& alloc,
  413. rapidjson::Value& inObject, const char* name, const std::string& value)
  414. {
  415. rapidjson::Value v;
  416. v.SetString(value.c_str(), value.length(), alloc);
  417. inObject.AddMember(rapidjson::StringRef(name), v, alloc);
  418. }
  419. void JsonHelper::AddBool(rapidjson::Document::AllocatorType& alloc,
  420. rapidjson::Value& inObject, const char* name, bool value)
  421. {
  422. rapidjson::Value v(value);
  423. inObject.AddMember(rapidjson::StringRef(name), v, alloc);
  424. }
  425. void JsonHelper::AddVector3(rapidjson::Document::AllocatorType& alloc,
  426. rapidjson::Value& inObject, const char* name, const Vector3& value)
  427. {
  428. // Create an array
  429. rapidjson::Value v(rapidjson::kArrayType);
  430. // Push back elements
  431. v.PushBack(rapidjson::Value(value.x).Move(), alloc);
  432. v.PushBack(rapidjson::Value(value.y).Move(), alloc);
  433. v.PushBack(rapidjson::Value(value.z).Move(), alloc);
  434. // Add array to inObject
  435. inObject.AddMember(rapidjson::StringRef(name), v, alloc);
  436. }
  437. void JsonHelper::AddQuaternion(rapidjson::Document::AllocatorType& alloc,
  438. rapidjson::Value& inObject, const char* name, const Quaternion& value)
  439. {
  440. // Create an array
  441. rapidjson::Value v(rapidjson::kArrayType);
  442. // Push back elements
  443. v.PushBack(rapidjson::Value(value.x).Move(), alloc);
  444. v.PushBack(rapidjson::Value(value.y).Move(), alloc);
  445. v.PushBack(rapidjson::Value(value.z).Move(), alloc);
  446. v.PushBack(rapidjson::Value(value.w).Move(), alloc);
  447. // Add array to inObject
  448. inObject.AddMember(rapidjson::StringRef(name), v, alloc);
  449. }