ff7DataInstaller.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #include "ff7DataInstaller.h"
  2. #include <boost/filesystem.hpp>
  3. #include <boost/program_options.hpp>
  4. #include <OgreConfigFile.h>
  5. #include <OgreArchiveManager.h>
  6. #include <OgreMeshSerializer.h>
  7. #include <OgreSkeletonSerializer.h>
  8. #include <OgreMeshManager.h>
  9. #include <OgreRenderWindow.h>
  10. #include <OgreHardwarePixelBuffer.h>
  11. #include "QGearsGameState.h"
  12. #include "data/QGearsAFileManager.h"
  13. #include "data/QGearsBackgroundFileManager.h"
  14. #include "data/QGearsCameraMatrixFileManager.h"
  15. #include "data/QGearsHRCFileManager.h"
  16. #include "data/QGearsLZSFLevelFileManager.h"
  17. #include "data/QGearsPaletteFileManager.h"
  18. #include "data/QGearsPFileManager.h"
  19. #include "data/QGearsRSDFileManager.h"
  20. #include "data/QGearsTexCodec.h"
  21. #include "map/QGearsBackground2DFileManager.h"
  22. #include "map/QGearsWalkmeshFileManager.h"
  23. #include "data/FF7ModelListFileManager.h"
  24. #include "data/QGearsLGPArchiveFactory.h"
  25. #include "common/QGearsStringUtil.h"
  26. #include "common/FF7NameLookup.h"
  27. #include "data/QGearsTexCodec.h"
  28. #include "decompiler/sudm.h"
  29. #include <memory>
  30. FF7DataInstaller::FF7DataInstaller()
  31. #ifdef _DEBUG
  32. : mApp("plugins_d.cfg", "resources_d.cfg", "install_d.log")
  33. #else
  34. : mApp("plugins.cfg", "resources.cfg", "install.log")
  35. #endif
  36. {
  37. mApp.initOgre(true);
  38. }
  39. FF7DataInstaller::~FF7DataInstaller()
  40. {
  41. }
  42. void FF7DataInstaller::Convert(std::string inputDir, std::string outputDir, const std::vector<std::string>& files)
  43. {
  44. for (const auto& file : files)
  45. {
  46. if (file == "field/char.lgp")
  47. {
  48. /*
  49. auto fullPath = inputDir + file;
  50. mApp.getRoot()->addResourceLocation(fullPath, "LGP", "FFVII");
  51. ConvertFieldModels(fullPath, outputDir);
  52. mApp.getRoot()->removeResourceLocation(fullPath, "FFVII");*/
  53. }
  54. else if (file == "field/flevel.lgp")
  55. {
  56. auto fullPath = inputDir + file;
  57. mApp.getRoot()->addResourceLocation(fullPath, "LGP", "FFVIIFields");
  58. ConvertFields(fullPath, outputDir);
  59. mApp.getRoot()->removeResourceLocation(fullPath, "FFVIIFields");
  60. }
  61. }
  62. }
  63. // TOOD: Share with pc model exporter
  64. static void exportMesh(std::string outdir, const Ogre::MeshPtr &mesh)
  65. {
  66. Ogre::MeshSerializer mesh_ser;
  67. mesh_ser.exportMesh(mesh.getPointer(), outdir + mesh->getName());
  68. Ogre::SkeletonPtr skeleton(mesh->getSkeleton());
  69. Ogre::SkeletonSerializer sk_ser;
  70. sk_ser.exportSkeleton(skeleton.getPointer(), outdir + skeleton->getName());
  71. Ogre::Mesh::SubMeshIterator it(mesh->getSubMeshIterator());
  72. Ogre::MaterialSerializer mat_ser;
  73. size_t i(0);
  74. while (it.hasMoreElements())
  75. {
  76. Ogre::SubMesh *sub_mesh(it.getNext());
  77. Ogre::MaterialPtr mat(Ogre::MaterialManager::getSingleton().getByName(sub_mesh->getMaterialName()));
  78. if (!mat.isNull())
  79. {
  80. mat_ser.queueForExport(mat);
  81. }
  82. ++i;
  83. }
  84. QGears::String base_name;
  85. QGears::StringUtil::splitFull(mesh->getName(), base_name);
  86. mat_ser.exportQueued(outdir + base_name + QGears::EXT_MATERIAL);
  87. }
  88. void FF7DataInstaller::ConvertFieldModels(std::string archive, std::string outDir)
  89. {
  90. Ogre::StringVectorPtr resources = mApp.ResMgr()->listResourceNames("FFVII", "*.hrc");
  91. for (auto& resourceName : *resources)
  92. {
  93. if (QGears::StringUtil::endsWith(resourceName, ".hrc"))
  94. {
  95. //try
  96. {
  97. Ogre::ResourcePtr hrc = QGears::HRCFileManager::getSingleton().load(resourceName, "FFVII");
  98. Ogre::String baseName;
  99. QGears::StringUtil::splitBase(resourceName, baseName);
  100. auto meshName = QGears::FF7::NameLookup::model(baseName) + ".mesh";
  101. Ogre::MeshPtr mesh(Ogre::MeshManager::getSingleton().load(meshName, "FFVII"));
  102. Ogre::SkeletonPtr skeleton(mesh->getSkeleton());
  103. exportMesh(outDir, mesh);
  104. }
  105. // catch (const Ogre::Exception& ex)
  106. {
  107. // std::cout << "ERROR converting: " << resourceName << " Exception: " << ex.what() << std::endl;
  108. }
  109. }
  110. }
  111. /*
  112. TODO:
  113. To figure out what .a files relate to which .hrc files, we need to enumerate every field
  114. and check its model loader data. These are always Idle, Walk, Run and then field specific
  115. ordering.
  116. Model loader is section 3 of the field file.
  117. */
  118. }
  119. class FF7FieldScriptFormatter : public SUDM::IScriptFormatter
  120. {
  121. public:
  122. virtual bool ExcludeFunction(const std::string& ) override
  123. {
  124. // Include everything for now
  125. return false;
  126. }
  127. virtual std::string RenameIdentifer(const std::string& name) override
  128. {
  129. // Don't rename anything for now
  130. return name;
  131. }
  132. };
  133. static void FF7PcFieldToQGearsField(QGears::FLevelFilePtr& field, const std::string& outDir)
  134. {
  135. // Save out the tiles as a PNG image
  136. try
  137. {
  138. // Get the raw script bytes
  139. const std::vector<u8> rawFieldData = field->getRawScript();
  140. // Decompile to LUA
  141. FF7FieldScriptFormatter formatter;
  142. std::string luaScript = SUDM::FF7::Field::Decompile(field->getName(), rawFieldData, formatter);
  143. std::ofstream scriptFile(outDir + "/" + field->getName() + ".lua");
  144. if (scriptFile.is_open())
  145. {
  146. scriptFile << luaScript;
  147. }
  148. else
  149. {
  150. std::cerr << "Failed to open script file for writing" << std::endl;
  151. }
  152. }
  153. catch (const ::InternalDecompilerError& ex)
  154. {
  155. std::cerr << "InternalDecompilerError: " << ex.what() << std::endl;
  156. }
  157. // TODO: Insert triggers into LUA script
  158. //const QGears::ModelListFilePtr& models = field->getModelList();
  159. //const QGears::ModelListFile::ModelDescription& desc = models->getModels().at(0);
  160. // Write out the map file which links all the other files together for a given field
  161. {
  162. TiXmlDocument doc;
  163. std::unique_ptr<TiXmlElement> element(new TiXmlElement("map"));
  164. // Script
  165. std::unique_ptr<TiXmlElement> xmlScriptElement(new TiXmlElement("script"));
  166. xmlScriptElement->SetAttribute("file_name", field->getName() + ".lua");
  167. element->LinkEndChild(xmlScriptElement.release());
  168. // Background
  169. std::unique_ptr<TiXmlElement> xmlBackground2d(new TiXmlElement("background2d"));
  170. xmlBackground2d->SetAttribute("file_name", field->getName() + "_bg.xml");
  171. element->LinkEndChild(xmlBackground2d.release());
  172. // walkmesh
  173. std::unique_ptr<TiXmlElement> xmlWalkmesh(new TiXmlElement("walkmesh"));
  174. xmlWalkmesh->SetAttribute("file_name", field->getName() + "_wm.xml");
  175. element->LinkEndChild(xmlWalkmesh.release());
  176. // TODO: movement_rotation - degree
  177. // TODO: entity_script - name
  178. // TODO: entity_model - name, file_name, position, direction
  179. // TODO: entity_trigger - name, point1, point2, enabled
  180. // TODO: entity_point - name, position, rotation
  181. doc.LinkEndChild(element.release());
  182. doc.SaveFile(outDir + "/" + field->getName() + ".xml");
  183. }
  184. const QGears::PaletteFilePtr& pal = field->getPalette();
  185. const QGears::BackgroundFilePtr& bg = field->getBackground();
  186. std::unique_ptr<Ogre::Image> bgImage(bg->createImage(pal));
  187. bgImage->save(outDir + "/" + field->getName() + ".png");
  188. {
  189. TiXmlDocument doc;
  190. std::unique_ptr<TiXmlElement> element(new TiXmlElement("background2d"));
  191. // Magic constants
  192. const int kScaleUpFactor = 3;
  193. const int kPsxScreenWidth = 320;
  194. const int kPsxScreenHeight = 240;
  195. // Get texture atlas size
  196. const int width = bgImage->getWidth();
  197. const int height = bgImage->getHeight();
  198. const QGears::CameraMatrixFilePtr& camMatrix = field->getCameraMatrix();
  199. const Ogre::Vector3 position = camMatrix->getPosition();
  200. const Ogre::Quaternion orientation = camMatrix->getOrientation();
  201. const Ogre::Degree fov = camMatrix->getFov(static_cast<float>(kPsxScreenHeight));
  202. const QGears::TriggersFilePtr& triggers = field->getTriggers();
  203. const int min_x = triggers->getCameraRange().left * kScaleUpFactor;
  204. const int min_y = triggers->getCameraRange().top * kScaleUpFactor;
  205. const int max_x = triggers->getCameraRange().right * kScaleUpFactor;
  206. const int max_y = triggers->getCameraRange().bottom * kScaleUpFactor;
  207. element->SetAttribute("image", field->getName() + ".png");
  208. element->SetAttribute("position", Ogre::StringConverter::toString(position));
  209. element->SetAttribute("orientation", Ogre::StringConverter::toString(orientation));
  210. element->SetAttribute("fov", Ogre::StringConverter::toString(fov));
  211. element->SetAttribute("range", std::to_string(min_x) + " " + std::to_string(min_y) + " " + std::to_string(max_x) + " " + std::to_string(max_y));
  212. element->SetAttribute("clip", std::to_string(kPsxScreenWidth * kScaleUpFactor) + " " + std::to_string(kPsxScreenHeight * kScaleUpFactor));
  213. // Write out the *_BG.XML data
  214. auto& layers = bg->getLayers();
  215. for (const auto& layer : layers)
  216. {
  217. // TODO: Should we only output tiles to construct enabled layers?
  218. // if (layer.enabled)
  219. {
  220. for (const QGears::BackgroundFile::SpriteData& sprite : layer.sprites)
  221. {
  222. std::unique_ptr<TiXmlElement> xmlElement(new TiXmlElement("tile"));
  223. xmlElement->SetAttribute("destination",
  224. Ogre::StringConverter::toString(sprite.dst.x * kScaleUpFactor) + " " +
  225. Ogre::StringConverter::toString(sprite.dst.y * kScaleUpFactor));
  226. xmlElement->SetAttribute("width", Ogre::StringConverter::toString(sprite.width * kScaleUpFactor));
  227. xmlElement->SetAttribute("height", Ogre::StringConverter::toString(sprite.height * kScaleUpFactor));
  228. // Each tile is added to a big texture atlas with hard coded size of 1024x1024, convert UV's to the 0.0f to 1.0f range
  229. const float u0 = static_cast<float>(sprite.src.x) / bgImage->getWidth();
  230. const float v0 = static_cast<float>(sprite.src.y) / bgImage->getHeight();
  231. const float u1 = static_cast<float>(sprite.src.x + sprite.width) / bgImage->getWidth();
  232. const float v1 = static_cast<float>(sprite.src.y + sprite.height) / bgImage->getHeight();
  233. xmlElement->SetAttribute("uv",
  234. Ogre::StringConverter::toString(u0) + " " + Ogre::StringConverter::toString(v0) + " " +
  235. Ogre::StringConverter::toString(u1) + " " + Ogre::StringConverter::toString(v1)
  236. );
  237. // TODO: Figure out how to scale this value correctly
  238. xmlElement->SetAttribute("depth", "999" /* Ogre::StringConverter::toString(static_cast<float>(sprite.depth) / (4096.0f/10.0f))*/);
  239. // TODO: Copied from DatFile::AddTile - add to common method
  240. Ogre::String blending_str = "";
  241. if (sprite.blending == 0)
  242. {
  243. blending_str = "alpha";
  244. }
  245. else if (sprite.blending == 1 || sprite.blending == 3) // 3 is source + 0.25 * destination
  246. {
  247. blending_str = "add";
  248. }
  249. else if (sprite.blending == 2)
  250. {
  251. blending_str = "subtract";
  252. }
  253. else
  254. {
  255. blending_str = "unknown";
  256. }
  257. xmlElement->SetAttribute("blending", blending_str);
  258. element->LinkEndChild(xmlElement.release());
  259. }
  260. }
  261. }
  262. doc.LinkEndChild(element.release());
  263. doc.SaveFile(outDir + "/" + field->getName() + "_bg.xml");
  264. }
  265. {
  266. // Save out the walk mesh as XML
  267. const QGears::WalkmeshFilePtr& walkmesh = field->getWalkmesh();
  268. TiXmlDocument doc;
  269. std::unique_ptr<TiXmlElement> element(new TiXmlElement("walkmesh"));
  270. for (QGears::WalkmeshFile::Triangle& tri : walkmesh->getTriangles())
  271. {
  272. std::unique_ptr<TiXmlElement> xmlElement(new TiXmlElement("triangle"));
  273. xmlElement->SetAttribute("a", Ogre::StringConverter::toString(tri.a));
  274. xmlElement->SetAttribute("b", Ogre::StringConverter::toString(tri.b));
  275. xmlElement->SetAttribute("c", Ogre::StringConverter::toString(tri.c));
  276. xmlElement->SetAttribute("a_b", std::to_string(tri.access_side[0]));
  277. xmlElement->SetAttribute("b_c", std::to_string(tri.access_side[1]));
  278. xmlElement->SetAttribute("c_a", std::to_string(tri.access_side[2]));
  279. element->LinkEndChild(xmlElement.release());
  280. }
  281. doc.LinkEndChild(element.release());
  282. doc.SaveFile(outDir + "/" + field->getName() + "_wm.xml");
  283. }
  284. }
  285. void FF7DataInstaller::ConvertFields(std::string archive, std::string outDir)
  286. {
  287. // Everything in here is a field
  288. Ogre::StringVectorPtr resources = mApp.ResMgr()->listResourceNames("FFVIIFields", "*");
  289. for (auto& resourceName : *resources)
  290. {
  291. if (!QGears::StringUtil::endsWith(resourceName, ".tex")
  292. && !QGears::StringUtil::endsWith(resourceName, ".tut")
  293. && !QGears::StringUtil::endsWith(resourceName, ".siz")
  294. && resourceName != "maplist" && resourceName == "md1_2")
  295. {
  296. //try
  297. {
  298. QGears::FLevelFilePtr field = QGears::LZSFLevelFileManager::getSingleton().load(resourceName, "FFVIIFields").staticCast<QGears::FLevelFile>();
  299. FF7PcFieldToQGearsField(field, outDir);
  300. }
  301. /*
  302. catch (const Ogre::Exception& ex)
  303. {
  304. std::cout << "ERROR converting: " << resourceName << " Exception: " << ex.what() << std::endl;
  305. }
  306. catch (const std::exception& ex)
  307. {
  308. std::cout << "ERROR converting: " << resourceName << " Exception: " << ex.what() << std::endl;
  309. }*/
  310. }
  311. }
  312. }