json_exporter.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. /*
  2. Assimp2Json
  3. Copyright (c) 2011, Alexander C. Gessler
  4. Licensed under a 3-clause BSD license. See the LICENSE file for more information.
  5. */
  6. #ifndef ASSIMP_BUILD_NO_EXPORT
  7. #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
  8. #include <assimp/scene.h>
  9. #include <assimp/Exporter.hpp>
  10. #include <assimp/IOStream.hpp>
  11. #include <assimp/IOSystem.hpp>
  12. #include <assimp/Importer.hpp>
  13. #include <cassert>
  14. #include <limits>
  15. #include <memory>
  16. #include <sstream>
  17. #define CURRENT_FORMAT_VERSION 100
  18. // grab scoped_ptr from assimp to avoid a dependency on boost.
  19. //#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
  20. #include "mesh_splitter.h"
  21. extern "C" {
  22. #include "cencode.h"
  23. }
  24. namespace Assimp {
  25. void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
  26. // small utility class to simplify serializing the aiScene to Json
  27. class JSONWriter {
  28. public:
  29. enum {
  30. Flag_DoNotIndent = 0x1,
  31. Flag_WriteSpecialFloats = 0x2,
  32. };
  33. JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
  34. out(out), first(), flags(flags) {
  35. // make sure that all formatting happens using the standard, C locale and not the user's current locale
  36. buff.imbue(std::locale("C"));
  37. }
  38. ~JSONWriter() {
  39. Flush();
  40. }
  41. void Flush() {
  42. const std::string s = buff.str();
  43. out.Write(s.c_str(), s.length(), 1);
  44. buff.clear();
  45. }
  46. void PushIndent() {
  47. indent += '\t';
  48. }
  49. void PopIndent() {
  50. indent.erase(indent.end() - 1);
  51. }
  52. void Key(const std::string &name) {
  53. AddIndentation();
  54. Delimit();
  55. buff << '\"' + name + "\": ";
  56. }
  57. template <typename Literal>
  58. void Element(const Literal &name) {
  59. AddIndentation();
  60. Delimit();
  61. LiteralToString(buff, name) << '\n';
  62. }
  63. template <typename Literal>
  64. void SimpleValue(const Literal &s) {
  65. LiteralToString(buff, s) << '\n';
  66. }
  67. void SimpleValue(const void *buffer, size_t len) {
  68. base64_encodestate s;
  69. base64_init_encodestate(&s);
  70. char *const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
  71. const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s);
  72. cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
  73. // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines
  74. // (only escaped ones). Remove any newlines in out.
  75. for (char *cur = cur_out; *cur; ++cur) {
  76. if (*cur == '\n') {
  77. *cur = ' ';
  78. }
  79. }
  80. buff << '\"' << cur_out << "\"\n";
  81. delete[] cur_out;
  82. }
  83. void StartObj(bool is_element = false) {
  84. // if this appears as a plain array element, we need to insert a delimiter and we should also indent it
  85. if (is_element) {
  86. AddIndentation();
  87. if (!first) {
  88. buff << ',';
  89. }
  90. }
  91. first = true;
  92. buff << "{\n";
  93. PushIndent();
  94. }
  95. void EndObj() {
  96. PopIndent();
  97. AddIndentation();
  98. first = false;
  99. buff << "}\n";
  100. }
  101. void StartArray(bool is_element = false) {
  102. // if this appears as a plain array element, we need to insert a delimiter and we should also indent it
  103. if (is_element) {
  104. AddIndentation();
  105. if (!first) {
  106. buff << ',';
  107. }
  108. }
  109. first = true;
  110. buff << "[\n";
  111. PushIndent();
  112. }
  113. void EndArray() {
  114. PopIndent();
  115. AddIndentation();
  116. buff << "]\n";
  117. first = false;
  118. }
  119. void AddIndentation() {
  120. if (!(flags & Flag_DoNotIndent)) {
  121. buff << indent;
  122. }
  123. }
  124. void Delimit() {
  125. if (!first) {
  126. buff << ',';
  127. } else {
  128. buff << ' ';
  129. first = false;
  130. }
  131. }
  132. private:
  133. template <typename Literal>
  134. std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
  135. stream << s;
  136. return stream;
  137. }
  138. std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
  139. std::string t;
  140. // escape backslashes and single quotes, both would render the JSON invalid if left as is
  141. t.reserve(s.length);
  142. for (size_t i = 0; i < s.length; ++i) {
  143. if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') {
  144. t.push_back('\\');
  145. }
  146. t.push_back(s.data[i]);
  147. }
  148. stream << "\"";
  149. stream << t;
  150. stream << "\"";
  151. return stream;
  152. }
  153. std::stringstream &LiteralToString(std::stringstream &stream, float f) {
  154. if (!std::numeric_limits<float>::is_iec559) {
  155. // on a non IEEE-754 platform, we make no assumptions about the representation or existence
  156. // of special floating-point numbers.
  157. stream << f;
  158. return stream;
  159. }
  160. // JSON does not support writing Inf/Nan
  161. // [RFC 4672: "Numeric values that cannot be represented as sequences of digits
  162. // (such as Infinity and NaN) are not permitted."]
  163. // Nevertheless, many parsers will accept the special keywords Infinity, -Infinity and NaN
  164. if (std::numeric_limits<float>::infinity() == fabs(f)) {
  165. if (flags & Flag_WriteSpecialFloats) {
  166. stream << (f < 0 ? "\"-" : "\"") + std::string("Infinity\"");
  167. return stream;
  168. }
  169. // we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
  170. // std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
  171. stream << "0.0";
  172. return stream;
  173. }
  174. // f!=f is the most reliable test for NaNs that I know of
  175. else if (f != f) {
  176. if (flags & Flag_WriteSpecialFloats) {
  177. stream << "\"NaN\"";
  178. return stream;
  179. }
  180. // we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr
  181. // std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl;
  182. stream << "0.0";
  183. return stream;
  184. }
  185. stream << f;
  186. return stream;
  187. }
  188. private:
  189. Assimp::IOStream &out;
  190. std::string indent, newline;
  191. std::stringstream buff;
  192. bool first;
  193. unsigned int flags;
  194. };
  195. void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
  196. out.StartArray(is_elem);
  197. out.Element(ai.x);
  198. out.Element(ai.y);
  199. out.Element(ai.z);
  200. out.EndArray();
  201. }
  202. void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
  203. out.StartArray(is_elem);
  204. out.Element(ai.w);
  205. out.Element(ai.x);
  206. out.Element(ai.y);
  207. out.Element(ai.z);
  208. out.EndArray();
  209. }
  210. void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
  211. out.StartArray(is_elem);
  212. out.Element(ai.r);
  213. out.Element(ai.g);
  214. out.Element(ai.b);
  215. out.EndArray();
  216. }
  217. void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
  218. out.StartArray(is_elem);
  219. for (unsigned int x = 0; x < 4; ++x) {
  220. for (unsigned int y = 0; y < 4; ++y) {
  221. out.Element(ai[x][y]);
  222. }
  223. }
  224. out.EndArray();
  225. }
  226. void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
  227. out.StartObj(is_elem);
  228. out.Key("name");
  229. out.SimpleValue(ai.mName);
  230. out.Key("offsetmatrix");
  231. Write(out, ai.mOffsetMatrix, false);
  232. out.Key("weights");
  233. out.StartArray();
  234. for (unsigned int i = 0; i < ai.mNumWeights; ++i) {
  235. out.StartArray(true);
  236. out.Element(ai.mWeights[i].mVertexId);
  237. out.Element(ai.mWeights[i].mWeight);
  238. out.EndArray();
  239. }
  240. out.EndArray();
  241. out.EndObj();
  242. }
  243. void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
  244. out.StartArray(is_elem);
  245. for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
  246. out.Element(ai.mIndices[i]);
  247. }
  248. out.EndArray();
  249. }
  250. void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
  251. out.StartObj(is_elem);
  252. out.Key("name");
  253. out.SimpleValue(ai.mName);
  254. out.Key("materialindex");
  255. out.SimpleValue(ai.mMaterialIndex);
  256. out.Key("primitivetypes");
  257. out.SimpleValue(ai.mPrimitiveTypes);
  258. out.Key("vertices");
  259. out.StartArray();
  260. for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
  261. out.Element(ai.mVertices[i].x);
  262. out.Element(ai.mVertices[i].y);
  263. out.Element(ai.mVertices[i].z);
  264. }
  265. out.EndArray();
  266. if (ai.HasNormals()) {
  267. out.Key("normals");
  268. out.StartArray();
  269. for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
  270. out.Element(ai.mNormals[i].x);
  271. out.Element(ai.mNormals[i].y);
  272. out.Element(ai.mNormals[i].z);
  273. }
  274. out.EndArray();
  275. }
  276. if (ai.HasTangentsAndBitangents()) {
  277. out.Key("tangents");
  278. out.StartArray();
  279. for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
  280. out.Element(ai.mTangents[i].x);
  281. out.Element(ai.mTangents[i].y);
  282. out.Element(ai.mTangents[i].z);
  283. }
  284. out.EndArray();
  285. out.Key("bitangents");
  286. out.StartArray();
  287. for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
  288. out.Element(ai.mBitangents[i].x);
  289. out.Element(ai.mBitangents[i].y);
  290. out.Element(ai.mBitangents[i].z);
  291. }
  292. out.EndArray();
  293. }
  294. if (ai.GetNumUVChannels()) {
  295. out.Key("numuvcomponents");
  296. out.StartArray();
  297. for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
  298. out.Element(ai.mNumUVComponents[n]);
  299. }
  300. out.EndArray();
  301. out.Key("texturecoords");
  302. out.StartArray();
  303. for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) {
  304. const unsigned int numc = ai.mNumUVComponents[n] ? ai.mNumUVComponents[n] : 2;
  305. out.StartArray(true);
  306. for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
  307. for (unsigned int c = 0; c < numc; ++c) {
  308. out.Element(ai.mTextureCoords[n][i][c]);
  309. }
  310. }
  311. out.EndArray();
  312. }
  313. out.EndArray();
  314. }
  315. if (ai.GetNumColorChannels()) {
  316. out.Key("colors");
  317. out.StartArray();
  318. for (unsigned int n = 0; n < ai.GetNumColorChannels(); ++n) {
  319. out.StartArray(true);
  320. for (unsigned int i = 0; i < ai.mNumVertices; ++i) {
  321. out.Element(ai.mColors[n][i].r);
  322. out.Element(ai.mColors[n][i].g);
  323. out.Element(ai.mColors[n][i].b);
  324. out.Element(ai.mColors[n][i].a);
  325. }
  326. out.EndArray();
  327. }
  328. out.EndArray();
  329. }
  330. if (ai.mNumBones) {
  331. out.Key("bones");
  332. out.StartArray();
  333. for (unsigned int n = 0; n < ai.mNumBones; ++n) {
  334. Write(out, *ai.mBones[n]);
  335. }
  336. out.EndArray();
  337. }
  338. out.Key("faces");
  339. out.StartArray();
  340. for (unsigned int n = 0; n < ai.mNumFaces; ++n) {
  341. Write(out, ai.mFaces[n]);
  342. }
  343. out.EndArray();
  344. out.EndObj();
  345. }
  346. void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
  347. out.StartObj(is_elem);
  348. out.Key("name");
  349. out.SimpleValue(ai.mName);
  350. out.Key("transformation");
  351. Write(out, ai.mTransformation, false);
  352. if (ai.mNumMeshes) {
  353. out.Key("meshes");
  354. out.StartArray();
  355. for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
  356. out.Element(ai.mMeshes[n]);
  357. }
  358. out.EndArray();
  359. }
  360. if (ai.mNumChildren) {
  361. out.Key("children");
  362. out.StartArray();
  363. for (unsigned int n = 0; n < ai.mNumChildren; ++n) {
  364. Write(out, *ai.mChildren[n]);
  365. }
  366. out.EndArray();
  367. }
  368. out.EndObj();
  369. }
  370. void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
  371. out.StartObj(is_elem);
  372. out.Key("properties");
  373. out.StartArray();
  374. for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
  375. const aiMaterialProperty *const prop = ai.mProperties[i];
  376. out.StartObj(true);
  377. out.Key("key");
  378. out.SimpleValue(prop->mKey);
  379. out.Key("semantic");
  380. out.SimpleValue(prop->mSemantic);
  381. out.Key("index");
  382. out.SimpleValue(prop->mIndex);
  383. out.Key("type");
  384. out.SimpleValue(prop->mType);
  385. out.Key("value");
  386. switch (prop->mType) {
  387. case aiPTI_Float:
  388. if (prop->mDataLength / sizeof(float) > 1) {
  389. out.StartArray();
  390. for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
  391. out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
  392. }
  393. out.EndArray();
  394. } else {
  395. out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
  396. }
  397. break;
  398. case aiPTI_Integer:
  399. if (prop->mDataLength / sizeof(int) > 1) {
  400. out.StartArray();
  401. for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
  402. out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
  403. }
  404. out.EndArray();
  405. } else {
  406. out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
  407. }
  408. break;
  409. case aiPTI_String: {
  410. aiString s;
  411. aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
  412. out.SimpleValue(s);
  413. } break;
  414. case aiPTI_Buffer: {
  415. // binary data is written as series of hex-encoded octets
  416. out.SimpleValue(prop->mData, prop->mDataLength);
  417. } break;
  418. default:
  419. assert(false);
  420. }
  421. out.EndObj();
  422. }
  423. out.EndArray();
  424. out.EndObj();
  425. }
  426. void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
  427. out.StartObj(is_elem);
  428. out.Key("width");
  429. out.SimpleValue(ai.mWidth);
  430. out.Key("height");
  431. out.SimpleValue(ai.mHeight);
  432. out.Key("formathint");
  433. out.SimpleValue(aiString(ai.achFormatHint));
  434. out.Key("data");
  435. if (!ai.mHeight) {
  436. out.SimpleValue(ai.pcData, ai.mWidth);
  437. } else {
  438. out.StartArray();
  439. for (unsigned int y = 0; y < ai.mHeight; ++y) {
  440. out.StartArray(true);
  441. for (unsigned int x = 0; x < ai.mWidth; ++x) {
  442. const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
  443. out.StartArray(true);
  444. out.Element(static_cast<unsigned int>(tx.r));
  445. out.Element(static_cast<unsigned int>(tx.g));
  446. out.Element(static_cast<unsigned int>(tx.b));
  447. out.Element(static_cast<unsigned int>(tx.a));
  448. out.EndArray();
  449. }
  450. out.EndArray();
  451. }
  452. out.EndArray();
  453. }
  454. out.EndObj();
  455. }
  456. void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
  457. out.StartObj(is_elem);
  458. out.Key("name");
  459. out.SimpleValue(ai.mName);
  460. out.Key("type");
  461. out.SimpleValue(ai.mType);
  462. if (ai.mType == aiLightSource_SPOT || ai.mType == aiLightSource_UNDEFINED) {
  463. out.Key("angleinnercone");
  464. out.SimpleValue(ai.mAngleInnerCone);
  465. out.Key("angleoutercone");
  466. out.SimpleValue(ai.mAngleOuterCone);
  467. }
  468. out.Key("attenuationconstant");
  469. out.SimpleValue(ai.mAttenuationConstant);
  470. out.Key("attenuationlinear");
  471. out.SimpleValue(ai.mAttenuationLinear);
  472. out.Key("attenuationquadratic");
  473. out.SimpleValue(ai.mAttenuationQuadratic);
  474. out.Key("diffusecolor");
  475. Write(out, ai.mColorDiffuse, false);
  476. out.Key("specularcolor");
  477. Write(out, ai.mColorSpecular, false);
  478. out.Key("ambientcolor");
  479. Write(out, ai.mColorAmbient, false);
  480. if (ai.mType != aiLightSource_POINT) {
  481. out.Key("direction");
  482. Write(out, ai.mDirection, false);
  483. }
  484. if (ai.mType != aiLightSource_DIRECTIONAL) {
  485. out.Key("position");
  486. Write(out, ai.mPosition, false);
  487. }
  488. out.EndObj();
  489. }
  490. void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
  491. out.StartObj(is_elem);
  492. out.Key("name");
  493. out.SimpleValue(ai.mNodeName);
  494. out.Key("prestate");
  495. out.SimpleValue(ai.mPreState);
  496. out.Key("poststate");
  497. out.SimpleValue(ai.mPostState);
  498. if (ai.mNumPositionKeys) {
  499. out.Key("positionkeys");
  500. out.StartArray();
  501. for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
  502. const aiVectorKey &pos = ai.mPositionKeys[n];
  503. out.StartArray(true);
  504. out.Element(pos.mTime);
  505. Write(out, pos.mValue);
  506. out.EndArray();
  507. }
  508. out.EndArray();
  509. }
  510. if (ai.mNumRotationKeys) {
  511. out.Key("rotationkeys");
  512. out.StartArray();
  513. for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
  514. const aiQuatKey &rot = ai.mRotationKeys[n];
  515. out.StartArray(true);
  516. out.Element(rot.mTime);
  517. Write(out, rot.mValue);
  518. out.EndArray();
  519. }
  520. out.EndArray();
  521. }
  522. if (ai.mNumScalingKeys) {
  523. out.Key("scalingkeys");
  524. out.StartArray();
  525. for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
  526. const aiVectorKey &scl = ai.mScalingKeys[n];
  527. out.StartArray(true);
  528. out.Element(scl.mTime);
  529. Write(out, scl.mValue);
  530. out.EndArray();
  531. }
  532. out.EndArray();
  533. }
  534. out.EndObj();
  535. }
  536. void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
  537. out.StartObj(is_elem);
  538. out.Key("name");
  539. out.SimpleValue(ai.mName);
  540. out.Key("tickspersecond");
  541. out.SimpleValue(ai.mTicksPerSecond);
  542. out.Key("duration");
  543. out.SimpleValue(ai.mDuration);
  544. out.Key("channels");
  545. out.StartArray();
  546. for (unsigned int n = 0; n < ai.mNumChannels; ++n) {
  547. Write(out, *ai.mChannels[n]);
  548. }
  549. out.EndArray();
  550. out.EndObj();
  551. }
  552. void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
  553. out.StartObj(is_elem);
  554. out.Key("name");
  555. out.SimpleValue(ai.mName);
  556. out.Key("aspect");
  557. out.SimpleValue(ai.mAspect);
  558. out.Key("clipplanefar");
  559. out.SimpleValue(ai.mClipPlaneFar);
  560. out.Key("clipplanenear");
  561. out.SimpleValue(ai.mClipPlaneNear);
  562. out.Key("horizontalfov");
  563. out.SimpleValue(ai.mHorizontalFOV);
  564. out.Key("up");
  565. Write(out, ai.mUp, false);
  566. out.Key("lookat");
  567. Write(out, ai.mLookAt, false);
  568. out.EndObj();
  569. }
  570. void WriteFormatInfo(JSONWriter &out) {
  571. out.StartObj();
  572. out.Key("format");
  573. out.SimpleValue("\"assimp2json\"");
  574. out.Key("version");
  575. out.SimpleValue(CURRENT_FORMAT_VERSION);
  576. out.EndObj();
  577. }
  578. void Write(JSONWriter &out, const aiScene &ai) {
  579. out.StartObj();
  580. out.Key("__metadata__");
  581. WriteFormatInfo(out);
  582. out.Key("rootnode");
  583. Write(out, *ai.mRootNode, false);
  584. out.Key("flags");
  585. out.SimpleValue(ai.mFlags);
  586. if (ai.HasMeshes()) {
  587. out.Key("meshes");
  588. out.StartArray();
  589. for (unsigned int n = 0; n < ai.mNumMeshes; ++n) {
  590. Write(out, *ai.mMeshes[n]);
  591. }
  592. out.EndArray();
  593. }
  594. if (ai.HasMaterials()) {
  595. out.Key("materials");
  596. out.StartArray();
  597. for (unsigned int n = 0; n < ai.mNumMaterials; ++n) {
  598. Write(out, *ai.mMaterials[n]);
  599. }
  600. out.EndArray();
  601. }
  602. if (ai.HasAnimations()) {
  603. out.Key("animations");
  604. out.StartArray();
  605. for (unsigned int n = 0; n < ai.mNumAnimations; ++n) {
  606. Write(out, *ai.mAnimations[n]);
  607. }
  608. out.EndArray();
  609. }
  610. if (ai.HasLights()) {
  611. out.Key("lights");
  612. out.StartArray();
  613. for (unsigned int n = 0; n < ai.mNumLights; ++n) {
  614. Write(out, *ai.mLights[n]);
  615. }
  616. out.EndArray();
  617. }
  618. if (ai.HasCameras()) {
  619. out.Key("cameras");
  620. out.StartArray();
  621. for (unsigned int n = 0; n < ai.mNumCameras; ++n) {
  622. Write(out, *ai.mCameras[n]);
  623. }
  624. out.EndArray();
  625. }
  626. if (ai.HasTextures()) {
  627. out.Key("textures");
  628. out.StartArray();
  629. for (unsigned int n = 0; n < ai.mNumTextures; ++n) {
  630. Write(out, *ai.mTextures[n]);
  631. }
  632. out.EndArray();
  633. }
  634. out.EndObj();
  635. }
  636. void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
  637. std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
  638. if (!str) {
  639. throw Assimp::DeadlyExportError("could not open output file");
  640. }
  641. // get a copy of the scene so we can modify it
  642. aiScene *scenecopy_tmp;
  643. aiCopyScene(scene, &scenecopy_tmp);
  644. try {
  645. // split meshes so they fit into a 16 bit index buffer
  646. MeshSplitter splitter;
  647. splitter.SetLimit(1 << 16);
  648. splitter.Execute(scenecopy_tmp);
  649. // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters
  650. JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
  651. Write(s, *scenecopy_tmp);
  652. } catch (...) {
  653. aiFreeScene(scenecopy_tmp);
  654. throw;
  655. }
  656. aiFreeScene(scenecopy_tmp);
  657. }
  658. } // namespace Assimp
  659. #endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
  660. #endif // ASSIMP_BUILD_NO_EXPORT