1 | /* |
2 | Open Asset Import Library (assimp) |
3 | ---------------------------------------------------------------------- |
4 | |
5 | Copyright (c) 2006-2017, assimp team |
6 | |
7 | All rights reserved. |
8 | |
9 | Redistribution and use of this software in source and binary forms, |
10 | with or without modification, are permitted provided that the |
11 | following conditions are met: |
12 | |
13 | * Redistributions of source code must retain the above |
14 | copyright notice, this list of conditions and the |
15 | following disclaimer. |
16 | |
17 | * Redistributions in binary form must reproduce the above |
18 | copyright notice, this list of conditions and the |
19 | following disclaimer in the documentation and/or other |
20 | materials provided with the distribution. |
21 | |
22 | * Neither the name of the assimp team, nor the names of its |
23 | contributors may be used to endorse or promote products |
24 | derived from this software without specific prior |
25 | written permission of the assimp team. |
26 | |
27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | |
39 | ---------------------------------------------------------------------- |
40 | */ |
41 | |
42 | /** @file glTFAsset.h |
43 | * Declares a glTF class to handle gltf/glb files |
44 | * |
45 | * glTF Extensions Support: |
46 | * KHR_binary_glTF: full |
47 | * KHR_materials_common: full |
48 | */ |
49 | #ifndef GLTFASSET_H_INC |
50 | #define GLTFASSET_H_INC |
51 | |
52 | #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER |
53 | |
54 | #include <map> |
55 | #include <string> |
56 | #include <list> |
57 | #include <vector> |
58 | #include <algorithm> |
59 | #include <stdexcept> |
60 | |
61 | #define RAPIDJSON_HAS_STDSTRING 1 |
62 | #include <rapidjson/rapidjson.h> |
63 | #include <rapidjson/document.h> |
64 | #include <rapidjson/error/en.h> |
65 | |
66 | #ifdef ASSIMP_API |
67 | # include <memory> |
68 | # include <assimp/DefaultIOSystem.h> |
69 | # include "ByteSwapper.h" |
70 | #else |
71 | # include <memory> |
72 | # define AI_SWAP4(p) |
73 | # define ai_assert |
74 | #endif |
75 | |
76 | |
77 | #if _MSC_VER > 1500 || (defined __GNUC___) |
78 | # define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP |
79 | # else |
80 | # define gltf_unordered_map map |
81 | #endif |
82 | |
83 | #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP |
84 | # include <unordered_map> |
85 | # if _MSC_VER > 1600 |
86 | # define gltf_unordered_map unordered_map |
87 | # else |
88 | # define gltf_unordered_map tr1::unordered_map |
89 | # endif |
90 | #endif |
91 | |
92 | namespace glTF |
93 | { |
94 | #ifdef ASSIMP_API |
95 | using Assimp::IOStream; |
96 | using Assimp::IOSystem; |
97 | using std::shared_ptr; |
98 | #else |
99 | using std::shared_ptr; |
100 | |
101 | typedef std::runtime_error DeadlyImportError; |
102 | typedef std::runtime_error DeadlyExportError; |
103 | |
104 | enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; |
105 | class IOSystem; |
106 | class IOStream |
107 | { |
108 | FILE* f; |
109 | public: |
110 | IOStream(FILE* file) : f(file) {} |
111 | ~IOStream() { fclose(f); f = 0; } |
112 | |
113 | size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } |
114 | size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } |
115 | int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } |
116 | size_t Tell() const { return ftell(f); } |
117 | |
118 | size_t FileSize() { |
119 | long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); |
120 | return size_t((Seek(p, aiOrigin_SET), len)); |
121 | } |
122 | }; |
123 | #endif |
124 | |
125 | using rapidjson::Value; |
126 | using rapidjson::Document; |
127 | |
128 | class Asset; |
129 | class AssetWriter; |
130 | |
131 | struct BufferView; // here due to cross-reference |
132 | struct Texture; |
133 | struct Light; |
134 | struct Skin; |
135 | |
136 | |
137 | // Vec/matrix types, as raw float arrays |
138 | typedef float (vec3)[3]; |
139 | typedef float (vec4)[4]; |
140 | typedef float (mat4)[16]; |
141 | |
142 | |
143 | namespace Util |
144 | { |
145 | void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); |
146 | |
147 | size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); |
148 | |
149 | inline size_t DecodeBase64(const char* in, uint8_t*& out) |
150 | { |
151 | return DecodeBase64(in, strlen(in), out); |
152 | } |
153 | |
154 | struct DataURI |
155 | { |
156 | const char* mediaType; |
157 | const char* charset; |
158 | bool base64; |
159 | const char* data; |
160 | size_t dataLength; |
161 | }; |
162 | |
163 | //! Check if a uri is a data URI |
164 | inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); |
165 | } |
166 | |
167 | |
168 | //! Magic number for GLB files |
169 | #define AI_GLB_MAGIC_NUMBER "glTF" |
170 | |
171 | #ifdef ASSIMP_API |
172 | #include "./../include/assimp/Compiler/pushpack1.h" |
173 | #endif |
174 | |
175 | //! For the KHR_binary_glTF extension (binary .glb file) |
176 | //! 20-byte header (+ the JSON + a "body" data section) |
177 | struct |
178 | { |
179 | uint8_t [4]; //!< Magic number: "glTF" |
180 | uint32_t ; //!< Version number (always 1 as of the last update) |
181 | uint32_t ; //!< Total length of the Binary glTF, including header, scene, and body, in bytes |
182 | uint32_t ; //!< Length, in bytes, of the glTF scene |
183 | uint32_t ; //!< Specifies the format of the glTF scene (see the SceneFormat enum) |
184 | } PACK_STRUCT; |
185 | |
186 | #ifdef ASSIMP_API |
187 | #include "./../include/assimp/Compiler/poppack1.h" |
188 | #endif |
189 | |
190 | |
191 | //! Values for the GLB_Header::sceneFormat field |
192 | enum SceneFormat |
193 | { |
194 | SceneFormat_JSON = 0 |
195 | }; |
196 | |
197 | //! Values for the mesh primitive modes |
198 | enum PrimitiveMode |
199 | { |
200 | PrimitiveMode_POINTS = 0, |
201 | PrimitiveMode_LINES = 1, |
202 | PrimitiveMode_LINE_LOOP = 2, |
203 | PrimitiveMode_LINE_STRIP = 3, |
204 | PrimitiveMode_TRIANGLES = 4, |
205 | PrimitiveMode_TRIANGLE_STRIP = 5, |
206 | PrimitiveMode_TRIANGLE_FAN = 6 |
207 | }; |
208 | |
209 | //! Values for the Accessor::componentType field |
210 | enum ComponentType |
211 | { |
212 | ComponentType_BYTE = 5120, |
213 | ComponentType_UNSIGNED_BYTE = 5121, |
214 | ComponentType_SHORT = 5122, |
215 | ComponentType_UNSIGNED_SHORT = 5123, |
216 | ComponentType_UNSIGNED_INT = 5125, |
217 | ComponentType_FLOAT = 5126 |
218 | }; |
219 | |
220 | inline unsigned int ComponentTypeSize(ComponentType t) |
221 | { |
222 | switch (t) { |
223 | case ComponentType_SHORT: |
224 | case ComponentType_UNSIGNED_SHORT: |
225 | return 2; |
226 | |
227 | case ComponentType_UNSIGNED_INT: |
228 | case ComponentType_FLOAT: |
229 | return 4; |
230 | |
231 | case ComponentType_BYTE: |
232 | case ComponentType_UNSIGNED_BYTE: |
233 | return 1; |
234 | default: |
235 | std::string err = "GLTF: Unsupported Component Type " ; |
236 | err += t; |
237 | throw DeadlyImportError(err); |
238 | } |
239 | } |
240 | |
241 | //! Values for the BufferView::target field |
242 | enum BufferViewTarget |
243 | { |
244 | BufferViewTarget_ARRAY_BUFFER = 34962, |
245 | BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963 |
246 | }; |
247 | |
248 | //! Values for the Sampler::magFilter field |
249 | enum SamplerMagFilter |
250 | { |
251 | SamplerMagFilter_Nearest = 9728, |
252 | SamplerMagFilter_Linear = 9729 |
253 | }; |
254 | |
255 | //! Values for the Sampler::minFilter field |
256 | enum SamplerMinFilter |
257 | { |
258 | SamplerMinFilter_Nearest = 9728, |
259 | SamplerMinFilter_Linear = 9729, |
260 | SamplerMinFilter_Nearest_Mipmap_Nearest = 9984, |
261 | SamplerMinFilter_Linear_Mipmap_Nearest = 9985, |
262 | SamplerMinFilter_Nearest_Mipmap_Linear = 9986, |
263 | SamplerMinFilter_Linear_Mipmap_Linear = 9987 |
264 | }; |
265 | |
266 | //! Values for the Sampler::wrapS and Sampler::wrapT field |
267 | enum SamplerWrap |
268 | { |
269 | SamplerWrap_Clamp_To_Edge = 33071, |
270 | SamplerWrap_Mirrored_Repeat = 33648, |
271 | SamplerWrap_Repeat = 10497 |
272 | }; |
273 | |
274 | //! Values for the Texture::format and Texture::internalFormat fields |
275 | enum TextureFormat |
276 | { |
277 | TextureFormat_ALPHA = 6406, |
278 | TextureFormat_RGB = 6407, |
279 | TextureFormat_RGBA = 6408, |
280 | TextureFormat_LUMINANCE = 6409, |
281 | TextureFormat_LUMINANCE_ALPHA = 6410 |
282 | }; |
283 | |
284 | //! Values for the Texture::target field |
285 | enum TextureTarget |
286 | { |
287 | TextureTarget_TEXTURE_2D = 3553 |
288 | }; |
289 | |
290 | //! Values for the Texture::type field |
291 | enum TextureType |
292 | { |
293 | TextureType_UNSIGNED_BYTE = 5121, |
294 | TextureType_UNSIGNED_SHORT_5_6_5 = 33635, |
295 | TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819, |
296 | TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820 |
297 | }; |
298 | |
299 | |
300 | //! Values for the Accessor::type field (helper class) |
301 | class AttribType |
302 | { |
303 | public: |
304 | enum Value |
305 | { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 }; |
306 | |
307 | private: |
308 | static const size_t NUM_VALUES = static_cast<size_t>(MAT4)+1; |
309 | |
310 | struct Info |
311 | { const char* name; unsigned int numComponents; }; |
312 | |
313 | template<int N> struct data |
314 | { static const Info infos[NUM_VALUES]; }; |
315 | |
316 | public: |
317 | inline static Value FromString(const char* str) |
318 | { |
319 | for (size_t i = 0; i < NUM_VALUES; ++i) { |
320 | if (strcmp(data<0>::infos[i].name, str) == 0) { |
321 | return static_cast<Value>(i); |
322 | } |
323 | } |
324 | return SCALAR; |
325 | } |
326 | |
327 | inline static const char* ToString(Value type) |
328 | { |
329 | return data<0>::infos[static_cast<size_t>(type)].name; |
330 | } |
331 | |
332 | inline static unsigned int GetNumComponents(Value type) |
333 | { |
334 | return data<0>::infos[static_cast<size_t>(type)].numComponents; |
335 | } |
336 | }; |
337 | |
338 | // must match the order of the AttribTypeTraits::Value enum! |
339 | template<int N> const AttribType::Info |
340 | AttribType::data<N>::infos[AttribType::NUM_VALUES] = { |
341 | { "SCALAR" , 1 }, { "VEC2" , 2 }, { "VEC3" , 3 }, { "VEC4" , 4 }, { "MAT2" , 4 }, { "MAT3" , 9 }, { "MAT4" , 16 } |
342 | }; |
343 | |
344 | |
345 | |
346 | //! A reference to one top-level object, which is valid |
347 | //! until the Asset instance is destroyed |
348 | template<class T> |
349 | class Ref |
350 | { |
351 | std::vector<T*>* vector; |
352 | unsigned int index; |
353 | |
354 | public: |
355 | Ref() : vector(0), index(0) {} |
356 | Ref(std::vector<T*>& vec, unsigned int idx) : vector(&vec), index(idx) {} |
357 | |
358 | inline unsigned int GetIndex() const |
359 | { return index; } |
360 | |
361 | operator bool() const |
362 | { return vector != 0; } |
363 | |
364 | T* operator->() |
365 | { return (*vector)[index]; } |
366 | |
367 | T& operator*() |
368 | { return *((*vector)[index]); } |
369 | }; |
370 | |
371 | //! Helper struct to represent values that might not be present |
372 | template<class T> |
373 | struct Nullable |
374 | { |
375 | T value; |
376 | bool isPresent; |
377 | |
378 | Nullable() : isPresent(false) {} |
379 | Nullable(T& val) : value(val), isPresent(true) {} |
380 | }; |
381 | |
382 | |
383 | //! Base classe for all glTF top-level objects |
384 | struct Object |
385 | { |
386 | std::string id; //!< The globally unique ID used to reference this object |
387 | std::string name; //!< The user-defined name of this object |
388 | |
389 | //! Objects marked as special are not exported (used to emulate the binary body buffer) |
390 | virtual bool IsSpecial() const |
391 | { return false; } |
392 | |
393 | virtual ~Object() {} |
394 | |
395 | //! Maps special IDs to another ID, where needed. Subclasses may override it (statically) |
396 | static const char* TranslateId(Asset& /*r*/, const char* id) |
397 | { return id; } |
398 | }; |
399 | |
400 | // |
401 | // Classes for each glTF top-level object type |
402 | // |
403 | |
404 | //! A typed view into a BufferView. A BufferView contains raw binary data. |
405 | //! An accessor provides a typed view into a BufferView or a subset of a BufferView |
406 | //! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. |
407 | struct Accessor : public Object |
408 | { |
409 | Ref<BufferView> bufferView; //!< The ID of the bufferView. (required) |
410 | unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) |
411 | unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0) |
412 | ComponentType componentType; //!< The datatype of components in the attribute. (required) |
413 | unsigned int count; //!< The number of attributes referenced by this accessor. (required) |
414 | AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) |
415 | std::vector<float> max; //!< Maximum value of each component in this attribute. |
416 | std::vector<float> min; //!< Minimum value of each component in this attribute. |
417 | |
418 | unsigned int GetNumComponents(); |
419 | unsigned int GetBytesPerComponent(); |
420 | unsigned int GetElementSize(); |
421 | |
422 | inline uint8_t* GetPointer(); |
423 | |
424 | template<class T> |
425 | bool (T*& outData); |
426 | |
427 | void WriteData(size_t count, const void* src_buffer, size_t src_stride); |
428 | |
429 | //! Helper class to iterate the data |
430 | class Indexer |
431 | { |
432 | friend struct Accessor; |
433 | |
434 | Accessor& accessor; |
435 | uint8_t* data; |
436 | size_t elemSize, stride; |
437 | |
438 | Indexer(Accessor& acc); |
439 | |
440 | public: |
441 | |
442 | //! Accesses the i-th value as defined by the accessor |
443 | template<class T> |
444 | T GetValue(int i); |
445 | |
446 | //! Accesses the i-th value as defined by the accessor |
447 | inline unsigned int GetUInt(int i) |
448 | { |
449 | return GetValue<unsigned int>(i); |
450 | } |
451 | |
452 | inline bool IsValid() const |
453 | { |
454 | return data != 0; |
455 | } |
456 | }; |
457 | |
458 | inline Indexer GetIndexer() |
459 | { |
460 | return Indexer(*this); |
461 | } |
462 | |
463 | Accessor() {} |
464 | void Read(Value& obj, Asset& r); |
465 | }; |
466 | |
467 | //! A buffer points to binary geometry, animation, or skins. |
468 | struct Buffer : public Object |
469 | { |
470 | /********************* Types *********************/ |
471 | public: |
472 | |
473 | enum Type |
474 | { |
475 | Type_arraybuffer, |
476 | Type_text |
477 | }; |
478 | |
479 | /// \struct SEncodedRegion |
480 | /// Descriptor of encoded region in "bufferView". |
481 | struct SEncodedRegion |
482 | { |
483 | const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes. |
484 | const size_t EncodedData_Length;///< Size of encoded region, in bytes. |
485 | uint8_t* const DecodedData;///< Cached encoded data. |
486 | const size_t DecodedData_Length;///< Size of decoded region, in bytes. |
487 | const std::string ID;///< ID of the region. |
488 | |
489 | /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) |
490 | /// Constructor. |
491 | /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. |
492 | /// \param [in] pEncodedData_Length - size of encoded region, in bytes. |
493 | /// \param [in] pDecodedData - pointer to decoded data array. |
494 | /// \param [in] pDecodedData_Length - size of encoded region, in bytes. |
495 | /// \param [in] pID - ID of the region. |
496 | SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) |
497 | : Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) |
498 | {} |
499 | |
500 | /// \fn ~SEncodedRegion() |
501 | /// Destructor. |
502 | ~SEncodedRegion() { delete [] DecodedData; } |
503 | }; |
504 | |
505 | /******************* Variables *******************/ |
506 | |
507 | //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) |
508 | size_t byteLength; //!< The length of the buffer in bytes. (default: 0) |
509 | //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") |
510 | |
511 | Type type; |
512 | |
513 | /// \var EncodedRegion_Current |
514 | /// Pointer to currently active encoded region. |
515 | /// Why not decoding all regions at once and not to set one buffer with decoded data? |
516 | /// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded |
517 | /// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But |
518 | /// offset is counted for another regions is encoded. |
519 | /// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data: |
520 | /// M1_E0, M1_E1, M2_E0, M2_E1. |
521 | /// After decoding you'll get: |
522 | /// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3. |
523 | /// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like |
524 | /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4} |
525 | /// but in real life you'll get: |
526 | /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4} |
527 | /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded. |
528 | /// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished |
529 | /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data. |
530 | /// |
531 | /// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in |
532 | /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory. |
533 | SEncodedRegion* EncodedRegion_Current; |
534 | |
535 | private: |
536 | |
537 | shared_ptr<uint8_t> mData; //!< Pointer to the data |
538 | bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) |
539 | |
540 | /// \var EncodedRegion_List |
541 | /// List of encoded regions. |
542 | std::list<SEncodedRegion*> EncodedRegion_List; |
543 | |
544 | /******************* Functions *******************/ |
545 | |
546 | public: |
547 | |
548 | Buffer(); |
549 | ~Buffer(); |
550 | |
551 | void Read(Value& obj, Asset& r); |
552 | |
553 | bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); |
554 | |
555 | /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) |
556 | /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data. |
557 | /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. |
558 | /// \param [in] pEncodedData_Length - size of encoded region, in bytes. |
559 | /// \param [in] pDecodedData - pointer to decoded data array. |
560 | /// \param [in] pDecodedData_Length - size of encoded region, in bytes. |
561 | /// \param [in] pID - ID of the region. |
562 | void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID); |
563 | |
564 | /// \fn void EncodedRegion_SetCurrent(const std::string& pID) |
565 | /// Select current encoded region by ID. \sa EncodedRegion_Current. |
566 | /// \param [in] pID - ID of the region. |
567 | void EncodedRegion_SetCurrent(const std::string& pID); |
568 | |
569 | /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) |
570 | /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions. |
571 | /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. |
572 | /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. |
573 | /// \param [in] pReplace_Data - pointer to array with new data for buffer. |
574 | /// \param [in] pReplace_Count - count of bytes in new data. |
575 | /// \return true - if successfully replaced, false if input arguments is out of range. |
576 | bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); |
577 | |
578 | size_t AppendData(uint8_t* data, size_t length); |
579 | void Grow(size_t amount); |
580 | |
581 | uint8_t* GetPointer() |
582 | { return mData.get(); } |
583 | |
584 | void MarkAsSpecial() |
585 | { mIsSpecial = true; } |
586 | |
587 | bool IsSpecial() const |
588 | { return mIsSpecial; } |
589 | |
590 | std::string GetURI() |
591 | { return std::string(this->id) + ".bin" ; } |
592 | |
593 | static const char* TranslateId(Asset& r, const char* id); |
594 | }; |
595 | |
596 | //! A view into a buffer generally representing a subset of the buffer. |
597 | struct BufferView : public Object |
598 | { |
599 | Ref<Buffer> buffer; //! The ID of the buffer. (required) |
600 | size_t byteOffset; //! The offset into the buffer in bytes. (required) |
601 | size_t byteLength; //! The length of the bufferView in bytes. (default: 0) |
602 | |
603 | BufferViewTarget target; //! The target that the WebGL buffer should be bound to. |
604 | |
605 | void Read(Value& obj, Asset& r); |
606 | }; |
607 | |
608 | struct Camera : public Object |
609 | { |
610 | enum Type |
611 | { |
612 | Perspective, |
613 | Orthographic |
614 | }; |
615 | |
616 | Type type; |
617 | |
618 | union |
619 | { |
620 | struct { |
621 | float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one) |
622 | float yfov; //!<The floating - point vertical field of view in radians. (required) |
623 | float zfar; //!<The floating - point distance to the far clipping plane. (required) |
624 | float znear; //!< The floating - point distance to the near clipping plane. (required) |
625 | } perspective; |
626 | |
627 | struct { |
628 | float xmag; //! The floating-point horizontal magnification of the view. (required) |
629 | float ymag; //! The floating-point vertical magnification of the view. (required) |
630 | float zfar; //! The floating-point distance to the far clipping plane. (required) |
631 | float znear; //! The floating-point distance to the near clipping plane. (required) |
632 | } ortographic; |
633 | }; |
634 | |
635 | Camera() {} |
636 | void Read(Value& obj, Asset& r); |
637 | }; |
638 | |
639 | |
640 | //! Image data used to create a texture. |
641 | struct Image : public Object |
642 | { |
643 | std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required) |
644 | |
645 | Ref<BufferView> bufferView; |
646 | |
647 | std::string mimeType; |
648 | |
649 | int width, height; |
650 | |
651 | private: |
652 | uint8_t* mData; |
653 | size_t mDataLength; |
654 | |
655 | public: |
656 | |
657 | Image(); |
658 | void Read(Value& obj, Asset& r); |
659 | |
660 | inline bool HasData() const |
661 | { return mDataLength > 0; } |
662 | |
663 | inline size_t GetDataLength() const |
664 | { return mDataLength; } |
665 | |
666 | inline const uint8_t* GetData() const |
667 | { return mData; } |
668 | |
669 | inline uint8_t* StealData(); |
670 | |
671 | inline void SetData(uint8_t* data, size_t length, Asset& r); |
672 | }; |
673 | |
674 | //! Holds a material property that can be a texture or a color |
675 | struct TexProperty |
676 | { |
677 | Ref<Texture> texture; |
678 | vec4 color; |
679 | }; |
680 | |
681 | //! The material appearance of a primitive. |
682 | struct Material : public Object |
683 | { |
684 | //Ref<Sampler> source; //!< The ID of the technique. |
685 | //std::gltf_unordered_map<std::string, std::string> values; //!< A dictionary object of parameter values. |
686 | |
687 | //! Techniques defined by KHR_materials_common |
688 | enum Technique |
689 | { |
690 | Technique_undefined = 0, |
691 | Technique_BLINN, |
692 | Technique_PHONG, |
693 | Technique_LAMBERT, |
694 | Technique_CONSTANT |
695 | }; |
696 | |
697 | TexProperty ambient; |
698 | TexProperty diffuse; |
699 | TexProperty specular; |
700 | TexProperty emission; |
701 | |
702 | bool doubleSided; |
703 | bool transparent; |
704 | float transparency; |
705 | float shininess; |
706 | |
707 | Technique technique; |
708 | |
709 | Material() { SetDefaults(); } |
710 | void Read(Value& obj, Asset& r); |
711 | void SetDefaults(); |
712 | }; |
713 | |
714 | //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene. |
715 | struct Mesh : public Object |
716 | { |
717 | typedef std::vector< Ref<Accessor> > AccessorList; |
718 | |
719 | struct Primitive |
720 | { |
721 | PrimitiveMode mode; |
722 | |
723 | struct Attributes { |
724 | AccessorList position, normal, texcoord, color, joint, jointmatrix, weight; |
725 | } attributes; |
726 | |
727 | Ref<Accessor> indices; |
728 | |
729 | Ref<Material> material; |
730 | }; |
731 | |
732 | /// \struct SExtension |
733 | /// Extension used for mesh. |
734 | struct SExtension |
735 | { |
736 | /// \enum EType |
737 | /// Type of extension. |
738 | enum EType |
739 | { |
740 | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
741 | Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorithm. |
742 | #endif |
743 | |
744 | Unknown |
745 | }; |
746 | |
747 | EType Type;///< Type of extension. |
748 | |
749 | /// \fn SExtension |
750 | /// Constructor. |
751 | /// \param [in] pType - type of extension. |
752 | SExtension(const EType pType) |
753 | : Type(pType) |
754 | {} |
755 | |
756 | virtual ~SExtension() { |
757 | // empty |
758 | } |
759 | }; |
760 | |
761 | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
762 | /// \struct SCompression_Open3DGC |
763 | /// Compression of mesh data using Open3DGC algorithm. |
764 | struct SCompression_Open3DGC : public SExtension |
765 | { |
766 | using SExtension::Type; |
767 | |
768 | std::string Buffer;///< ID of "buffer" used for storing compressed data. |
769 | size_t Offset;///< Offset in "bufferView" where compressed data are stored. |
770 | size_t Count;///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type". |
771 | bool Binary;///< If true then "binary" mode is used for coding, if false - "ascii" mode. |
772 | size_t IndicesCount;///< Count of indices in mesh. |
773 | size_t VerticesCount;///< Count of vertices in mesh. |
774 | // AttribType::Value Type;///< Is always "SCALAR". |
775 | // ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121). |
776 | |
777 | /// \fn SCompression_Open3DGC |
778 | /// Constructor. |
779 | SCompression_Open3DGC() |
780 | : SExtension(Compression_Open3DGC) { |
781 | // empty |
782 | } |
783 | |
784 | virtual ~SCompression_Open3DGC() { |
785 | // empty |
786 | } |
787 | }; |
788 | #endif |
789 | |
790 | std::vector<Primitive> primitives; |
791 | std::list<SExtension*> Extension;///< List of extensions used in mesh. |
792 | |
793 | Mesh() {} |
794 | |
795 | /// \fn ~Mesh() |
796 | /// Destructor. |
797 | ~Mesh() { for(std::list<SExtension*>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; } |
798 | |
799 | /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) |
800 | /// Get mesh data from JSON-object and place them to root asset. |
801 | /// \param [in] pJSON_Object - reference to pJSON-object from which data are read. |
802 | /// \param [out] pAsset_Root - reference to root assed where data will be stored. |
803 | void Read(Value& pJSON_Object, Asset& pAsset_Root); |
804 | |
805 | #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC |
806 | /// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) |
807 | /// Decode part of "buffer" which encoded with Open3DGC algorithm. |
808 | /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region. |
809 | /// \param [out] pAsset_Root - reference to root assed where data will be stored. |
810 | void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root); |
811 | #endif |
812 | }; |
813 | |
814 | struct Node : public Object |
815 | { |
816 | std::vector< Ref<Node> > children; |
817 | std::vector< Ref<Mesh> > meshes; |
818 | |
819 | Nullable<mat4> matrix; |
820 | Nullable<vec3> translation; |
821 | Nullable<vec4> rotation; |
822 | Nullable<vec3> scale; |
823 | |
824 | Ref<Camera> camera; |
825 | Ref<Light> light; |
826 | |
827 | std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. |
828 | Ref<Skin> skin; //!< The ID of the skin referenced by this node. |
829 | std::string jointName; //!< Name used when this node is a joint in a skin. |
830 | |
831 | Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper. |
832 | |
833 | Node() {} |
834 | void Read(Value& obj, Asset& r); |
835 | }; |
836 | |
837 | struct Program : public Object |
838 | { |
839 | Program() {} |
840 | void Read(Value& obj, Asset& r); |
841 | }; |
842 | |
843 | |
844 | struct Sampler : public Object |
845 | { |
846 | SamplerMagFilter magFilter; //!< The texture magnification filter. (required) |
847 | SamplerMinFilter minFilter; //!< The texture minification filter. (required) |
848 | SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required) |
849 | SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required) |
850 | |
851 | Sampler() {} |
852 | void Read(Value& obj, Asset& r); |
853 | void SetDefaults(); |
854 | }; |
855 | |
856 | struct Scene : public Object |
857 | { |
858 | std::vector< Ref<Node> > nodes; |
859 | |
860 | Scene() {} |
861 | void Read(Value& obj, Asset& r); |
862 | }; |
863 | |
864 | struct Shader : public Object |
865 | { |
866 | Shader() {} |
867 | void Read(Value& obj, Asset& r); |
868 | }; |
869 | |
870 | struct Skin : public Object |
871 | { |
872 | Nullable<mat4> bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order. |
873 | Ref<Accessor> inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices. |
874 | std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. |
875 | std::string name; //!< The user-defined name of this object. |
876 | |
877 | Skin() {} |
878 | void Read(Value& obj, Asset& r); |
879 | }; |
880 | |
881 | struct Technique : public Object |
882 | { |
883 | struct Parameters |
884 | { |
885 | |
886 | }; |
887 | |
888 | struct States |
889 | { |
890 | |
891 | }; |
892 | |
893 | struct Functions |
894 | { |
895 | |
896 | }; |
897 | |
898 | Technique() {} |
899 | void Read(Value& obj, Asset& r); |
900 | }; |
901 | |
902 | //! A texture and its sampler. |
903 | struct Texture : public Object |
904 | { |
905 | Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required) |
906 | Ref<Image> source; //!< The ID of the image used by this texture. (required) |
907 | |
908 | //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) |
909 | //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA) |
910 | |
911 | //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D) |
912 | //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE) |
913 | |
914 | Texture() {} |
915 | void Read(Value& obj, Asset& r); |
916 | }; |
917 | |
918 | |
919 | //! A light (from KHR_materials_common extension) |
920 | struct Light : public Object |
921 | { |
922 | enum Type |
923 | { |
924 | Type_undefined, |
925 | Type_ambient, |
926 | Type_directional, |
927 | Type_point, |
928 | Type_spot |
929 | }; |
930 | |
931 | Type type; |
932 | |
933 | vec4 color; |
934 | float distance; |
935 | float constantAttenuation; |
936 | float linearAttenuation; |
937 | float quadraticAttenuation; |
938 | float falloffAngle; |
939 | float falloffExponent; |
940 | |
941 | Light() {} |
942 | void Read(Value& obj, Asset& r); |
943 | |
944 | void SetDefaults(); |
945 | }; |
946 | |
947 | struct Animation : public Object |
948 | { |
949 | struct AnimSampler { |
950 | std::string id; //!< The ID of this sampler. |
951 | std::string input; //!< The ID of a parameter in this animation to use as key-frame input. |
952 | std::string interpolation; //!< Type of interpolation algorithm to use between key-frames. |
953 | std::string output; //!< The ID of a parameter in this animation to use as key-frame output. |
954 | }; |
955 | |
956 | struct AnimChannel { |
957 | std::string sampler; //!< The ID of one sampler present in the containing animation's samplers property. |
958 | |
959 | struct AnimTarget { |
960 | Ref<Node> id; //!< The ID of the node to animate. |
961 | std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale"). |
962 | } target; |
963 | }; |
964 | |
965 | struct AnimParameters { |
966 | Ref<Accessor> TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values. |
967 | Ref<Accessor> rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors. |
968 | Ref<Accessor> scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. |
969 | Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. |
970 | }; |
971 | |
972 | // AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. |
973 | // AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. |
974 | // AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data. |
975 | |
976 | std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. |
977 | AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. |
978 | std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data. |
979 | |
980 | Animation() {} |
981 | void Read(Value& obj, Asset& r); |
982 | }; |
983 | |
984 | |
985 | //! Base class for LazyDict that acts as an interface |
986 | class LazyDictBase |
987 | { |
988 | public: |
989 | virtual ~LazyDictBase() {} |
990 | |
991 | virtual void AttachToDocument(Document& doc) = 0; |
992 | virtual void DetachFromDocument() = 0; |
993 | |
994 | virtual void WriteObjects(AssetWriter& writer) = 0; |
995 | }; |
996 | |
997 | |
998 | template<class T> |
999 | class LazyDict; |
1000 | |
1001 | //! (Implemented in glTFAssetWriter.h) |
1002 | template<class T> |
1003 | void WriteLazyDict(LazyDict<T>& d, AssetWriter& w); |
1004 | |
1005 | |
1006 | //! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID |
1007 | //! It is the owner the loaded objects, so when it is destroyed it also deletes them |
1008 | template<class T> |
1009 | class LazyDict : public LazyDictBase |
1010 | { |
1011 | friend class Asset; |
1012 | friend class AssetWriter; |
1013 | |
1014 | typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict; |
1015 | |
1016 | std::vector<T*> mObjs; //! The read objects |
1017 | Dict mObjsById; //! The read objects accessible by id |
1018 | const char* mDictId; //! ID of the dictionary object |
1019 | const char* mExtId; //! ID of the extension defining the dictionary |
1020 | Value* mDict; //! JSON dictionary object |
1021 | Asset& mAsset; //! The asset instance |
1022 | |
1023 | void AttachToDocument(Document& doc); |
1024 | void DetachFromDocument(); |
1025 | |
1026 | void WriteObjects(AssetWriter& writer) |
1027 | { WriteLazyDict<T>(*this, writer); } |
1028 | |
1029 | Ref<T> Add(T* obj); |
1030 | |
1031 | public: |
1032 | LazyDict(Asset& asset, const char* dictId, const char* extId = 0); |
1033 | ~LazyDict(); |
1034 | |
1035 | Ref<T> Get(const char* id); |
1036 | Ref<T> Get(unsigned int i); |
1037 | Ref<T> Get(const std::string& pID) { return Get(pID.c_str()); } |
1038 | |
1039 | Ref<T> Create(const char* id); |
1040 | Ref<T> Create(const std::string& id) |
1041 | { return Create(id.c_str()); } |
1042 | |
1043 | inline unsigned int Size() const |
1044 | { return unsigned(mObjs.size()); } |
1045 | |
1046 | inline T& operator[](size_t i) |
1047 | { return *mObjs[i]; } |
1048 | |
1049 | }; |
1050 | |
1051 | |
1052 | struct AssetMetadata |
1053 | { |
1054 | std::string copyright; //!< A copyright message suitable for display to credit the content creator. |
1055 | std::string generator; //!< Tool that generated this glTF model.Useful for debugging. |
1056 | bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false) |
1057 | |
1058 | struct { |
1059 | std::string api; //!< Specifies the target rendering API (default: "WebGL") |
1060 | std::string version; //!< Specifies the target rendering API (default: "1.0.3") |
1061 | } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {}) |
1062 | |
1063 | std::string version; //!< The glTF format version (should be 1.0) |
1064 | |
1065 | void Read(Document& doc); |
1066 | |
1067 | AssetMetadata() |
1068 | : premultipliedAlpha(false) |
1069 | , version("" ) |
1070 | { |
1071 | } |
1072 | }; |
1073 | |
1074 | // |
1075 | // glTF Asset class |
1076 | // |
1077 | |
1078 | //! Root object for a glTF asset |
1079 | class Asset |
1080 | { |
1081 | typedef std::gltf_unordered_map<std::string, int> IdMap; |
1082 | |
1083 | template<class T> |
1084 | friend class LazyDict; |
1085 | |
1086 | friend struct Buffer; // To access OpenFile |
1087 | |
1088 | friend class AssetWriter; |
1089 | |
1090 | private: |
1091 | IOSystem* mIOSystem; |
1092 | |
1093 | std::string mCurrentAssetDir; |
1094 | |
1095 | size_t mSceneLength; |
1096 | size_t mBodyOffset, mBodyLength; |
1097 | |
1098 | std::vector<LazyDictBase*> mDicts; |
1099 | |
1100 | IdMap mUsedIds; |
1101 | |
1102 | Ref<Buffer> mBodyBuffer; |
1103 | |
1104 | Asset(Asset&); |
1105 | Asset& operator=(const Asset&); |
1106 | |
1107 | public: |
1108 | |
1109 | //! Keeps info about the enabled extensions |
1110 | struct Extensions |
1111 | { |
1112 | bool KHR_binary_glTF; |
1113 | bool KHR_materials_common; |
1114 | |
1115 | } extensionsUsed; |
1116 | |
1117 | AssetMetadata asset; |
1118 | |
1119 | |
1120 | // Dictionaries for each type of object |
1121 | |
1122 | LazyDict<Accessor> accessors; |
1123 | LazyDict<Animation> animations; |
1124 | LazyDict<Buffer> buffers; |
1125 | LazyDict<BufferView> bufferViews; |
1126 | LazyDict<Camera> cameras; |
1127 | LazyDict<Image> images; |
1128 | LazyDict<Material> materials; |
1129 | LazyDict<Mesh> meshes; |
1130 | LazyDict<Node> nodes; |
1131 | //LazyDict<Program> programs; |
1132 | LazyDict<Sampler> samplers; |
1133 | LazyDict<Scene> scenes; |
1134 | //LazyDict<Shader> shaders; |
1135 | LazyDict<Skin> skins; |
1136 | //LazyDict<Technique> techniques; |
1137 | LazyDict<Texture> textures; |
1138 | |
1139 | LazyDict<Light> lights; // KHR_materials_common ext |
1140 | |
1141 | Ref<Scene> scene; |
1142 | |
1143 | public: |
1144 | Asset(IOSystem* io = 0) |
1145 | : mIOSystem(io) |
1146 | , asset() |
1147 | , accessors (*this, "accessors" ) |
1148 | , animations (*this, "animations" ) |
1149 | , buffers (*this, "buffers" ) |
1150 | , bufferViews (*this, "bufferViews" ) |
1151 | , cameras (*this, "cameras" ) |
1152 | , images (*this, "images" ) |
1153 | , materials (*this, "materials" ) |
1154 | , meshes (*this, "meshes" ) |
1155 | , nodes (*this, "nodes" ) |
1156 | //, programs (*this, "programs") |
1157 | , samplers (*this, "samplers" ) |
1158 | , scenes (*this, "scenes" ) |
1159 | //, shaders (*this, "shaders") |
1160 | , skins (*this, "skins" ) |
1161 | //, techniques (*this, "techniques") |
1162 | , textures (*this, "textures" ) |
1163 | , lights (*this, "lights" , "KHR_materials_common" ) |
1164 | { |
1165 | memset(&extensionsUsed, 0, sizeof(extensionsUsed)); |
1166 | } |
1167 | |
1168 | //! Main function |
1169 | void Load(const std::string& file, bool isBinary = false); |
1170 | |
1171 | //! Enables the "KHR_binary_glTF" extension on the asset |
1172 | void SetAsBinary(); |
1173 | |
1174 | //! Search for an available name, starting from the given strings |
1175 | std::string FindUniqueID(const std::string& str, const char* suffix); |
1176 | |
1177 | Ref<Buffer> GetBodyBuffer() |
1178 | { return mBodyBuffer; } |
1179 | |
1180 | private: |
1181 | void (IOStream& stream); |
1182 | |
1183 | void ReadExtensionsUsed(Document& doc); |
1184 | |
1185 | |
1186 | IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); |
1187 | }; |
1188 | |
1189 | } |
1190 | |
1191 | // Include the implementation of the methods |
1192 | #include "glTFAsset.inl" |
1193 | |
1194 | #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER |
1195 | |
1196 | #endif // GLTFASSET_H_INC |
1197 | |