@@ -1949,6 +1949,7 @@ struct Scene : IScene
19491949 int getMeshCount () const override { return (int )m_meshes.size (); }
19501950 float getSceneFrameRate () const override { return m_scene_frame_rate; }
19511951 const GlobalSettings* getGlobalSettings () const override { return &m_settings; }
1952+ const Headers* getHeaders () const override { return &m_headers; }
19521953
19531954 const Object* const * getAllObjects () const override { return m_all_objects.empty () ? nullptr : &m_all_objects[0 ]; }
19541955
@@ -2052,6 +2053,7 @@ struct Scene : IScene
20522053 Root* m_root = nullptr ;
20532054 float m_scene_frame_rate = -1 ;
20542055 GlobalSettings m_settings;
2056+ Headers m_headers;
20552057
20562058 std::unordered_map<std::string, u64 > m_fake_ids;
20572059 std::unordered_map<u64 , ObjectPair> m_object_map;
@@ -3396,6 +3398,100 @@ static void parseGlobalSettings(const Element& root, Scene* scene)
33963398 }
33973399}
33983400
3401+ static void parseHeaders (const Element& root, Scene* scene)
3402+ {
3403+ const Element* headers = findChild (root, " FBXHeaderExtension" );
3404+ if (!headers) return ;
3405+
3406+ const Element* sceneInfo = findChild (*headers, " SceneInfo" );
3407+ if (sceneInfo)
3408+ {
3409+ bool is_p60 = false ;
3410+ const Element* props = findChild (*sceneInfo, " Properties70" );
3411+ if (!props)
3412+ {
3413+ is_p60 = true ;
3414+ props = findChild (*sceneInfo, " Properties60" );
3415+ if (!props) return ;
3416+ }
3417+
3418+ for (Element* node = props->child ; node; node = node->sibling )
3419+ {
3420+ if (!node->first_property ) continue ;
3421+
3422+ #define get_string_property (name, field ) if (node->first_property->value == name) \
3423+ { \
3424+ IElementProperty* prop = node->getProperty (scene->version <= 6100 ? 3 : 4 ); \
3425+ if (prop) \
3426+ { \
3427+ DataView value = prop->getValue (); \
3428+ char tmp[255 ]; \
3429+ value.toString (tmp); \
3430+ tmp[sizeof (tmp) - 1 ] = ' \0 ' ; \
3431+ size_t len = strlen (tmp) + 1 ; \
3432+ scene->m_headers .field = new char [len]; \
3433+ memcpy (scene->m_headers .field , tmp, len); \
3434+ } \
3435+ }
3436+
3437+ get_string_property (" DocumentUrl" , documentUrl);
3438+ get_string_property (" SrcDocumentUrl" , srcDocumentUrl);
3439+ get_string_property (" Original|ApplicationVendor" , originalApplicationVendor);
3440+ get_string_property (" Original|ApplicationName" , originalApplicationName);
3441+ get_string_property (" Original|ApplicationVersion" , originalApplicationVersion);
3442+ get_string_property (" Original|DateTime_GMT" , originalDateTimeGMT); // datetime stored as string using local culture, dirty, could be improved
3443+ get_string_property (" Original|Filename" , originalFilename);
3444+ get_string_property (" Original|ApplicationActiveProject" , originalApplicationActiveProject);
3445+ get_string_property (" Original|ApplicationNativeFile" , originalApplicationNativeFile); // Blender FBX export only
3446+ get_string_property (" LastSaved|ApplicationVendor" , lastSavedApplicationVendor);
3447+ get_string_property (" LastSaved|ApplicationName" , lastSavedApplicationName);
3448+ get_string_property (" LastSaved|ApplicationVersion" , lastSavedApplicationVersion);
3449+ get_string_property (" LastSaved|DateTime_GMT" , lastSavedDateTimeGMT); // datetime stored as string using local culture, dirty, could be improved
3450+
3451+ #undef get_string_property
3452+ }
3453+ }
3454+
3455+ for (Element* node = headers->child ; node; node = node->sibling )
3456+ {
3457+ if (!node->first_property ) continue ;
3458+
3459+ #define get_property (name, field, type, getter ) if (node->id == name) \
3460+ { \
3461+ IElementProperty* prop = node->getProperty (0 ); \
3462+ if (prop) \
3463+ { \
3464+ DataView value = prop->getValue (); \
3465+ scene->m_headers .field = (type)value.getter (); \
3466+ } \
3467+ }
3468+
3469+ #define get_string_property (name, field ) if (node->id == name) \
3470+ { \
3471+ IElementProperty* prop = node->getProperty (0 ); \
3472+ if (prop) \
3473+ { \
3474+ DataView value = prop->getValue (); \
3475+ char tmp[255 ]; \
3476+ value.toString (tmp); \
3477+ tmp[sizeof (tmp) - 1 ] = ' \0 ' ; \
3478+ size_t len = strlen (tmp) + 1 ; \
3479+ scene->m_headers .field = new char [len]; \
3480+ memcpy (scene->m_headers .field , tmp, len); \
3481+ } \
3482+ }
3483+
3484+ get_property (" FBXHeaderVersion" , fbxHeaderVersion, int , toInt);
3485+ get_property (" FBXVersion" , fbxVersion, int , toInt);
3486+ get_property (" EncryptionType" , encryptionType, int , toInt);
3487+ get_string_property (" Creator" , creator);
3488+ get_string_property (" CreationTime" , creationTime); // in Blender exports, not in 3ds max exports
3489+
3490+ #undef get_property
3491+ #undef get_string_property
3492+ }
3493+ }
3494+
33993495void sync_job_processor (JobFunction fn, void *, void * data, u32 size, u32 count) {
34003496 u8 * ptr = (u8 *)data;
34013497 for (u32 i = 0 ; i < count; ++i) {
@@ -4113,6 +4209,7 @@ IScene* load(const u8* data, usize size, u16 flags, JobProcessor job_processor,
41134209 if (!parseTakes (*scene.get ())) return nullptr ;
41144210 if (!parseObjects (*root.getValue (), *scene.get (), flags, scene->m_allocator , job_processor, job_user_ptr)) return nullptr ;
41154211 parseGlobalSettings (*root.getValue (), scene.get ());
4212+ parseHeaders (*root.getValue (), scene.get ());
41164213 if (!scene->finalize ()) return nullptr ;
41174214
41184215 return scene.release ();
0 commit comments