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