├── .gitignore ├── FBX Importer ├── DzFbxImporter.def ├── version.h ├── DzFbxImporter.rc ├── pluginmain.cpp ├── CMakeLists.txt ├── DzFbxImporter.h └── DzFbxImporter.cpp ├── cmake └── DzMocFiles.cmake ├── README.md ├── CMakeLists.txt └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # FBX SDK directory 35 | FBXSDK 36 | 37 | # build directory 38 | /build -------------------------------------------------------------------------------- /FBX Importer/DzFbxImporter.def: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; Copyright (C) 2002-2022 DAZ 3D, Inc. All Rights Reserved. 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 16 | 17 | LIBRARY dzfbximporter 18 | EXPORTS 19 | getSDKVersion @1 20 | getPluginDefinition @2 21 | SECTIONS 22 | .data READ WRITE 23 | -------------------------------------------------------------------------------- /FBX Importer/version.h: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | Copyright (C) 2012-2022 DAZ 3D, Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | **********************************************************************/ 16 | 17 | #pragma once 18 | 19 | #include "dzversion.h" 20 | 21 | // Version number for the FBX Importer plug-in 22 | #define PLUGIN_MAJOR 1 23 | #define PLUGIN_MINOR 4 24 | #define PLUGIN_REV 1 25 | #define PLUGIN_BUILD 0 26 | 27 | #define PLUGIN_VERSION DZ_MAKE_VERSION( PLUGIN_MAJOR, PLUGIN_MINOR, PLUGIN_REV, PLUGIN_BUILD ) 28 | 29 | 30 | -------------------------------------------------------------------------------- /FBX Importer/DzFbxImporter.rc: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // Copyright (C) 2002-2022 DAZ 3D, Inc. All Rights Reserved. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | ///////////////////////////////////////////////////////////////////////////// 16 | 17 | #include "version.h" 18 | #include "windows.h" 19 | 20 | #ifdef _WIN32 21 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 22 | #pragma code_page(1252) 23 | #endif //_WIN32 24 | 25 | ///////////////////////////////////////////////////////////////////////////// 26 | // 27 | // Version 28 | // 29 | ///////////////////////////////////////////////////////////////////////////// 30 | 31 | VS_VERSION_INFO VERSIONINFO 32 | FILEVERSION PLUGIN_MAJOR, PLUGIN_MINOR, PLUGIN_REV, PLUGIN_BUILD 33 | PRODUCTVERSION DZ_VERSION_MAJOR, DZ_VERSION_MINOR, DZ_VERSION_REV, DZ_VERSION_BUILD 34 | FILEFLAGSMASK 0x17L 35 | #ifdef _DEBUG 36 | FILEFLAGS 0x1L 37 | #else 38 | FILEFLAGS 0x0L 39 | #endif 40 | FILEOS 0x4L 41 | FILETYPE 0x2L 42 | FILESUBTYPE 0x0L 43 | BEGIN 44 | BLOCK "StringFileInfo" 45 | BEGIN 46 | BLOCK "040904b0" 47 | BEGIN 48 | VALUE "CompanyName", "Daz 3D, Inc." 49 | VALUE "FileDescription", "Daz FBX Importer Plug-in" 50 | VALUE "InternalName", "DzFBXImporter" 51 | VALUE "LegalCopyright", "Copyright (C) 2002-2022 Daz 3D, Inc." 52 | VALUE "ProductName", "Daz Studio" 53 | 54 | END 55 | END 56 | BLOCK "VarFileInfo" 57 | BEGIN 58 | VALUE "Translation", 0x409, 1200 59 | END 60 | END 61 | 62 | 63 | -------------------------------------------------------------------------------- /FBX Importer/pluginmain.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | Copyright (C) 2012-2022 DAZ 3D, Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | **********************************************************************/ 16 | 17 | /***************************** 18 | Include files 19 | *****************************/ 20 | #include "dzplugin.h" 21 | #include "dzapp.h" 22 | 23 | #include "version.h" 24 | #include "dzfbximporter.h" 25 | 26 | /***************************** 27 | Plugin Definition 28 | *****************************/ 29 | 30 | /** 31 | This macro creates the plugin definition, and the functions that are needed 32 | for Daz Studio to load the plugin. 33 | **/ 34 | DZ_PLUGIN_DEFINITION( "FBX Importer" ); 35 | 36 | /** 37 | This macro sets the author string for the plugin 38 | **/ 39 | DZ_PLUGIN_AUTHOR( "Daz 3D, Inc" ); 40 | 41 | /** 42 | This macro sets the version number for the plugin 43 | **/ 44 | DZ_PLUGIN_VERSION( PLUGIN_MAJOR, PLUGIN_MINOR, PLUGIN_REV, PLUGIN_BUILD ); 45 | 46 | /** 47 | This macro sets the description string for the plugin. This is a good place 48 | to provide specific information about the plugin, including an HTML link to 49 | any external documentation. Links are shown in the system default browser. 50 | **/ 51 | DZ_PLUGIN_DESCRIPTION( 52 | "Imports the Autodesk FBX format. " 53 | "

Source code is available on Github.

" 54 | "

This software contains Autodesk® FBX® code developed by Autodesk, Inc. " 55 | "Copyright 2013 Autodesk, Inc. All rights, reserved. Such code is provided \"as is\" " 56 | "and Autodesk, Inc. disclaims any and all warranties, whether express or implied, including " 57 | "without limitation the implied warranties of merchantability, fitness for a particular " 58 | "purpose or non-infringement of third party rights. In no event shall Autodesk, Inc. be liable " 59 | "for any direct, indirect, incidental, special, exemplary, or consequential damages (including, " 60 | "but not limited to, procurement of substitute goods or services; loss of use, data, or profits; " 61 | "or business interruption) however caused and on any theory of liability, whether in contract, " 62 | "strict liability, or tort (including negligence or otherwise) arising in any way out of such code.

" 63 | ); 64 | 65 | /** 66 | This macro adds this plugin's classes to the objects exported by the plugin, and specifies the 67 | GUID (Globally Unique Identifier) that makes this class unique from any other class 68 | that is available from Daz Studio or one of it's plug-ins. DO NOT USE the GUID below 69 | in your plug-in. Make sure that you generate a new GUID for every class that you export 70 | from your plug-in. To avoid potential conflicts, DO NOT USE the same class name in your own 71 | plugin. 72 | **/ 73 | DZ_PLUGIN_CLASS_GUID( DzFbxImporter, 4E0BDC3A-2B5C-4E21-A250-1327D5D6A92B ); 74 | -------------------------------------------------------------------------------- /cmake/DzMocFiles.cmake: -------------------------------------------------------------------------------- 1 | ####################################################################### 2 | # Copyright (C) 2016-2022 DAZ 3D, Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ####################################################################### 16 | 17 | macro( dz_moc_headers is_qt5_moc addtional_options outputList ) 18 | foreach(mocHeader ${ARGN}) 19 | get_filename_component(bareMocHeaderName ${mocHeader} NAME) 20 | if( ${is_qt5_moc} ) 21 | qt5_wrap_cpp( ${outputList} ${mocHeader} 22 | OPTIONS 23 | ${${addtional_options}} 24 | -f${bareMocHeaderName} ) 25 | else() 26 | qt4_wrap_cpp( ${outputList} ${mocHeader} 27 | OPTIONS 28 | ${${addtional_options}} 29 | -f${bareMocHeaderName} ) 30 | endif() 31 | list(APPEND ${outputList} ${sourceFile} ${mocHeader} ) 32 | endforeach() 33 | endmacro( dz_moc_headers ) 34 | 35 | macro( dz_uic_headers is_qt5 out_path addtional_options outputList ) 36 | #Adapted from qt4_wrap_ui found in Qt4Macros.cmake 37 | #BSD License, see cmake modules 38 | foreach(uicFile ${ARGN}) 39 | get_filename_component(outfile ${uicFile} NAME_WE) 40 | get_filename_component(infile ${uicFile} ABSOLUTE) 41 | set(outfile ${out_path}/ui_${outfile}.h) 42 | if( ${is_qt5} ) 43 | set(UIC_COMMAND Qt5::uic ) 44 | else() 45 | set(UIC_COMMAND Qt4::uic ) 46 | endif() 47 | add_custom_command(OUTPUT ${outfile} 48 | COMMAND ${UIC_COMMAND} 49 | ARGS ${${addtional_options}} -o ${outfile} ${infile} 50 | MAIN_DEPENDENCY ${infile} VERBATIM) 51 | list(APPEND ${outputList} ${outfile} ${uicFile}) 52 | endforeach() 53 | endmacro( dz_uic_headers ) 54 | 55 | 56 | macro( dz_rcc is_qt5 addtional_options outputList ) 57 | foreach(rccFile ${ARGN}) 58 | get_filename_component(bareFilename ${rccFile} NAME_WE) 59 | if( ${is_qt5} ) 60 | qt5_add_resources( ${outputList} ${rccFile} 61 | OPTIONS 62 | ${${addtional_options}} ) 63 | else() 64 | qt4_add_resources( ${outputList} ${rccFile} 65 | OPTIONS 66 | ${${addtional_options}} ) 67 | endif() 68 | list(APPEND ${outputList} ${sourceFile} ${rccFile} ) 69 | endforeach() 70 | endmacro( dz_rcc ) 71 | 72 | function(dz_source_subgroup name) 73 | string(REPLACE "/" "\\" folder_name ${name}) 74 | source_group("Header Files\\${folder_name}" REGULAR_EXPRESSION ".*/${name}/.*\\.[hH]") 75 | source_group("Source Files\\${folder_name}" REGULAR_EXPRESSION ".*/${name}/.*\\.c(|pp)") 76 | endfunction() 77 | 78 | function(dz_optimize_target target) 79 | if (MSVC) 80 | get_property(dz_current_rel_flags TARGET ${target} PROPERTY LINK_FLAGS_RELWITHDEBINFO) 81 | set_target_properties( 82 | ${target} 83 | PROPERTIES 84 | LINK_FLAGS_RELWITHDEBINFO "${dz_current_rel_flags} /OPT:REF /OPT:ICF /INCREMENTAL:NO" 85 | ) 86 | endif(MSVC) 87 | endfunction() 88 | 89 | function(dz_uac_linker_target target) 90 | if (MSVC) 91 | get_property(dz_linker_flags TARGET ${target} PROPERTY LINK_FLAGS) 92 | set_target_properties( 93 | ${target} 94 | PROPERTIES 95 | LINK_FLAGS "${dz_linker_flags} /MANIFESTUAC:\"level=asInvoker uiAccess=false\"" 96 | ) 97 | endif(MSVC) 98 | endfunction() 99 | 100 | function(dz_grow_stack_linker_target target) 101 | get_property(dz_linker_flags TARGET ${target} PROPERTY LINK_FLAGS) 102 | if (MSVC) 103 | set_target_properties( 104 | ${target} 105 | PROPERTIES 106 | LINK_FLAGS "${dz_linker_flags} /STACK:0x1000000" 107 | ) 108 | elseif(APPLE) 109 | set_target_properties( 110 | ${target} 111 | PROPERTIES 112 | LINK_FLAGS "${dz_linker_flags} -Wl,-stack_size -Wl,0x1000000" 113 | ) 114 | endif() 115 | endfunction() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daz Studio FBX Importer 2 | * Owner: [Daz 3D][OwnerURL] — [@Daz3d][TwitterURL] 3 | * License: [Apache License, Version 2.0][LicenseURL] - see ``LICENSE`` and ``NOTICE`` for more information. 4 | * Official Project: [github.com/daz3d/StudioFbxImporter][RepositoryURL] 5 | 6 | ## Prerequisites 7 | * **[Daz Studio][DazStudioURL]** application 8 | * 4.16.1.17 Public Build or newer 9 | * _Includes Qt 4.8.7 binaries_ (platform specific) 10 | * 4.20.0.17 General Release or newer 11 | * _Includes Qt 4.8.7 binaries_ (platform specific) 12 | * **Daz Studio SDK** 13 | * [Version 4.5+][DazStudioSDKURL] or newer 14 | * _Includes Qt 4.8.1 binaries_ 15 | * _Includes Qt 4.8 headers_ 16 | * **[FBX SDK][FBXSDKURL]** 17 | * Version [2016][FBXSDKArchiveURL] or newer 18 | * **[CMake][CMakeURL]** 19 | * Version 3.4.0 or newer 20 | * Operating System 21 | * Windows 7 or newer 22 | 23 | ## Build instructions 24 | * Download and install the **Daz Studio** application. 25 | * Note the installation path, it _may_ be needed in a later step. 26 | * Download and install the **Daz Studio SDK**. 27 | * Note the installation path, it _will_ be needed in a later step. 28 | * Download and install the **FBX SDK**. 29 | * Note the installation path _before the version number_, it _will_ be needed in a later step. 30 | * **CMake** is required to generate project files. 31 | * CMake can be used via the GUI tool, or the command line interface. 32 | * Using cmake-gui: 33 | * Launch the CMake GUI tool. 34 | * Click _Browse Source..._ to specify the path where this repository has been cloned locally. 35 | * Click _Browse Build..._ to specify the path where build files should be created - e.g., ``.../build/x64``. 36 | * Click _Configure_ to initialize the setup for this project. 37 | * Choose a generator from the list provided. 38 | * Optionally choose a platform (e.g., ``x64``) for the generator. 39 | * In the optional toolset field, enter ``v100`` to indicate use of the Visual Studio 2010 toolset. 40 | * _NOTE: Other compilers may face memory allocation/de-allocation issues._ 41 | * Click _Finish_ - CMake will begin processing and ultimately throw an error indicating a need to provide a valid path to the Daz Studio SDK. 42 | * Set the ``DAZ_SDK_DIR`` variable to the **Daz Studio SDK** installation path (as noted above). 43 | * Set the ``FBX_SDK_INSTALL_DIR`` variable to the **FBX SDK** installation path (as noted above). 44 | * Set the ``FBX_SDK_VERSION`` and ``FBX_SDK_VSTUDIO_VERSION`` variables to the version of the FBX SDK and corresponding Visual Studio version respectively 45 | * These variables are used to generate paths to the library files of the specified FBX SDK. 46 | * These variables allow for easy switching between multiple installed FBX SDK versions. 47 | * Click _Configure_ - the remaining ``FBX_SDK_`` prefixed variables will be automatically populated based on the variables described above. 48 | * The values of these ``FBX_SDK_`` prefixed variables may need to be adjusted to reflect machine specific configurations if ``FBX_CUSTOM_LAYOUT`` is enabled. 49 | * Click _Generate_ once the configuration has successfully completed to generate the project. 50 | * Using cmake command line: 51 | * ``cmake`` can be run at the root level of the repository with specific options, as shown in the following command: 52 | * ``cmake -B -G "Visual Studio 16" -T v100 -D DAZ_SDK_DIR= -D FBX_SDK_INSTALL_DIR= -D FBX_SDK_VERSION= -D FBX_SDK_VSTUDIO_VERSION=`` 53 | * ``-B`` will set the path to the generated files. 54 | * ``-G`` specifies the Visual Studio generator version. 55 | * ``-T`` will specify the compiler toolset. 56 | * ``-D`` is used for setting the cmake variables for the build. 57 | * Configuration and generation of project files are both performed using the above command. 58 | * Launch the project in Visual Studio and build the solution. 59 | * If the build is successful, copy ``dzfbximporter.dll`` from the project output directory. Paste the library to the ``plugins`` folder under Daz Studio install location. 60 | * This step will replace the existing FBX importer plugin file that is bundled with the application. 61 | * Installing the application again will replace this file to the version distributed with it. 62 | * Uninstalling the application will remove this file. 63 | * Alternatively, the previous step can be automated by setting the ``DAZ_STUDIO_EXE_DIR`` variable while generating the project. In this case, while building the solution, make sure to quit any active instances of Daz Studio. 64 | * _NOTE: Visual Studio may need to be run with admin privileges if the ``DAZ_STUDIO_EXE_DIR`` variable is pointing to a protected path like ``Program Files``._ 65 | * This step will replace the existing FBX importer plugin file that is bundled with the application. 66 | * Installing the application again will replace this file to the version distributed with it. 67 | * Uninstalling the application will remove this file. 68 | * Daz Studio is now installed with the built version of the plugin. 69 | 70 | [OwnerURL]: https://www.daz3d.com 71 | [TwitterURL]: https://twitter.com/Daz3d 72 | [LicenseURL]: http://www.apache.org/licenses/LICENSE-2.0 73 | [RepositoryURL]: https://github.com/daz3d/StudioFbxImporter 74 | [DazStudioURL]: https://www.daz3d.com/get_studio 75 | [DazStudioSDKURL]: https://www.daz3d.com/daz-studio-4-5-sdk 76 | [FBXSDKURL]: https://www.autodesk.com/products/fbx/overview 77 | [FBXSDKArchiveURL]: https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-archives 78 | [CMakeURL]: https://cmake.org 79 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ####################################################################### 2 | # Copyright (C) 2002-2022 DAZ 3D, Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ####################################################################### 16 | 17 | cmake_minimum_required( VERSION 3.4.0 ) 18 | 19 | project( "DAZ Studio Fbx Importer" ) 20 | 21 | set_property( GLOBAL PROPERTY USE_FOLDERS ON ) 22 | 23 | set( DAZ_STUDIO_EXE_DIR "" CACHE PATH "Path to DAZ Studio, needs to be installed to a writeable location." ) 24 | 25 | set( DAZ_SDK_DIR "" CACHE PATH "Path to root of the DAZ Studio SDK." ) 26 | if( NOT EXISTS ${DAZ_SDK_DIR} ) 27 | message( SEND_ERROR "Provide a valid path to the DAZ Studio SDK (DAZ_SDK_DIR)." ) 28 | return() 29 | endif() 30 | 31 | list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) 32 | include( DzMocFiles ) 33 | 34 | # Define platform specific variables 35 | if( WIN32 ) 36 | set( DZ_LIB_SUFFIX ".lib" ) 37 | set( DZ_BIN_SUFFIX ".dll" ) 38 | set( DZ_LIB_PREFIX "" ) 39 | set( UTIL_EXT ".exe" ) 40 | if( CMAKE_SIZEOF_VOID_P EQUAL 4 ) 41 | set( DZ_PLATFORM x86 ) 42 | set( DZ_MIXED_PLATFORM Win32 ) 43 | set( DZ_OS_PLATFORM Win32 ) 44 | elseif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 45 | set( DZ_PLATFORM x64 ) 46 | set( DZ_MIXED_PLATFORM x64 ) 47 | set( DZ_OS_PLATFORM Win64 ) 48 | else() 49 | message( FATAL_ERROR "Unknown architecture" ) 50 | endif() 51 | elseif( APPLE ) 52 | set( DZ_LIB_SUFFIX ".dylib" ) 53 | set( DZ_BIN_SUFFIX ".dylib" ) 54 | set( DZ_LIB_PREFIX "lib" ) 55 | set( UTIL_EXT "" ) 56 | if( CMAKE_SIZEOF_VOID_P EQUAL 4 ) 57 | set( DZ_PLATFORM x86 ) 58 | set( DZ_MIXED_PLATFORM Mac32 ) 59 | set( DZ_OS_PLATFORM Mac32 ) 60 | elseif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) 61 | set( DZ_PLATFORM x64 ) 62 | set( DZ_MIXED_PLATFORM Mac64 ) 63 | set( DZ_OS_PLATFORM Mac64 ) 64 | else() 65 | message( FATAL_ERROR "Unknown architecture" ) 66 | endif() 67 | set( CMAKE_MACOSX_RPATH TRUE ) 68 | set( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE ) 69 | else() 70 | message( FATAL_ERROR "Unknown architecture" ) 71 | endif( WIN32 ) 72 | 73 | set( DAZ_SDK_INCLUDE_DIR "${DAZ_SDK_DIR}/include" CACHE FILEPATH "Path to daz sdk includes." ) 74 | set( DAZ_SDK_CORE_RELATIVE_PATH "lib/${DZ_MIXED_PLATFORM}/${DZ_LIB_PREFIX}dzcore${DZ_LIB_SUFFIX}" ) 75 | set( DAZ_SDK_LIB "${DAZ_SDK_DIR}/${DAZ_SDK_CORE_RELATIVE_PATH}" CACHE FILEPATH "Path to dzcore." ) 76 | 77 | add_library( dzcore SHARED IMPORTED ) 78 | if( WIN32 ) 79 | set_property( TARGET dzcore APPEND PROPERTY IMPORTED_IMPLIB ${DAZ_SDK_LIB} ) 80 | else() 81 | set_property( TARGET dzcore APPEND PROPERTY IMPORTED_LOCATION ${DAZ_SDK_LIB} ) 82 | endif( WIN32 ) 83 | set_property( TARGET dzcore APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${DAZ_SDK_INCLUDE_DIR}" ) 84 | 85 | # Setup Qt from the DAZ Studio SDK 86 | if( WIN32 ) 87 | set( DAZ_SDK_QTCORE_LIBRARY "${DAZ_SDK_DIR}/lib/${DZ_MIXED_PLATFORM}/QtCore4.lib" ) 88 | elseif( APPLE ) 89 | set( DAZ_SDK_QTCORE_LIBRARY "${DAZ_SDK_DIR}/lib/${DZ_MIXED_PLATFORM}/QtCore.framework" ) 90 | endif() 91 | 92 | set( QT_QTCORE_LIBRARY_RELEASE ${DAZ_SDK_QTCORE_LIBRARY} ) 93 | set( QT_QMAKE_EXECUTABLE "${DAZ_SDK_DIR}/bin/${DZ_MIXED_PLATFORM}/qmake${UTIL_EXT}" ) 94 | set( QT_BINARY_DIR "${DAZ_SDK_DIR}/bin/${DZ_MIXED_PLATFORM}" ) 95 | set( QT_HEADERS_DIR "${DAZ_SDK_DIR}/include" ) 96 | set( QT_QTCORE_INCLUDE_DIR "${DAZ_SDK_DIR}/include/QtCore" ) 97 | 98 | # The Qt find module needs this folder, but our build does not, so just fake it 99 | file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/DUMMY_MKSPECS/default" ) 100 | set( QT_MKSPECS_DIR "${CMAKE_CURRENT_BINARY_DIR}/DUMMY_MKSPECS" ) 101 | 102 | find_package( Qt4 4.8.1 REQUIRED QtCore QtGui QtScript QtOpenGL QtNetwork QtSql QtXml ) 103 | 104 | set( DZSDK_QT_CORE_TARGET Qt4::QtCore ) 105 | set( DZSDK_QT_GUI_TARGET Qt4::QtGui ) 106 | set( DZSDK_QT_SCRIPT_TARGET Qt4::QtScript ) 107 | set( DZSDK_QT_OPENGL_TARGET Qt4::QtOpenGL ) 108 | set( DZSDK_QT_NETWORK_TARGET Qt4::QtNetwork ) 109 | set( DZSDK_QT_SQL_TARGET Qt4::QtSql ) 110 | set( DZSDK_QT_XML_TARGET Qt4::QtXml ) 111 | 112 | set( PLUGIN_MOC_OPTIONS 113 | "-I${DAZ_SDK_INCLUDE_DIR}" 114 | ) 115 | 116 | function( setup_standard_plugin_source_groups ) 117 | source_group( "Resource Files" REGULAR_EXPRESSION ".*\\.(def|rc|ico|icns|rgs)" ) 118 | source_group( "Source Files\\generated\\moc" REGULAR_EXPRESSION "/moc_.*\\.c(xx|pp)$" ) 119 | source_group( "Header Files\\generated\\ui files" REGULAR_EXPRESSION "/ui_.*\\.h$" ) 120 | source_group( "Source Files\\ui files" REGULAR_EXPRESSION ".*\\.ui$" ) 121 | endfunction() 122 | 123 | # If DAZ_STUDIO_EXE_DIR is not defined, the compiled result will be placed in the default CMake binary folder 124 | # If DAZ_STUDIO_EXE_DIR is defined, the compiled result placed in the Daz Studio ./plugins directory 125 | if( DAZ_STUDIO_EXE_DIR ) 126 | foreach( curConfig ${CMAKE_CONFIGURATION_TYPES} ) 127 | string( TOUPPER ${curConfig} curConfig ) 128 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${curConfig} ${DAZ_STUDIO_EXE_DIR}/plugins ) 129 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${curConfig} ${DAZ_STUDIO_EXE_DIR}/plugins ) 130 | endforeach() 131 | endif() 132 | 133 | add_subdirectory( "FBX Importer" ) 134 | -------------------------------------------------------------------------------- /FBX Importer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ####################################################################### 2 | # Copyright (C) 2016-2022 DAZ 3D, Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | ####################################################################### 16 | 17 | set( CMAKE_AUTOMOC ON ) 18 | set( CMAKE_INCLUDE_CURRENT_DIR ON ) 19 | 20 | set( DZ_PLUGIN_TGT_NAME dzfbximporter ) 21 | set( DZ_PLUGIN_PROJECT_NAME "FBX Importer" ) 22 | 23 | if( WIN32 ) 24 | set( OS_SOURCES 25 | DzFbxImporter.rc 26 | DzFbxImporter.def 27 | ) 28 | elseif( APPLE ) 29 | set( OS_SOURCES "" ) 30 | endif() 31 | 32 | set( PLUGIN_MOC_SOURCES "" ) 33 | 34 | dz_moc_headers( PLUGIN_MOC_OPTIONS PLUGIN_MOC_SOURCES 35 | dzfbximporter.h 36 | ) 37 | 38 | option( FBX_CUSTOM_LAYOUT "If the FBX SDK directory has a custom layout." OFF ) 39 | 40 | set( FBX_SDK_INSTALL_DIR "" CACHE PATH "Install directory of the FBX SDK." ) 41 | set( FBX_SDK_VERSION "" CACHE STRING "FBX SDK version, used for locating the path to the FBX SDK libraries." ) 42 | set( FBX_SDK_VSTUDIO_VERSION "" CACHE STRING "FBX SDK VS compiler version, used for locating the path to the FBX SDK libraries." ) 43 | 44 | set( FBX_SDK_ROOT_DIR "${FBX_SDK_INSTALL_DIR}/${FBX_SDK_VERSION}" CACHE PATH "Root directory of the FBX SDK." FORCE) 45 | set( FBX_SDK_LIB_ROOT_DIR "${FBX_SDK_ROOT_DIR}/lib/${FBX_SDK_VSTUDIO_VERSION}" CACHE PATH "Root directory of the FBX SDK." FORCE) 46 | 47 | if( NOT FBX_CUSTOM_LAYOUT ) 48 | set( FBX_SDK_DIR TRUE ) 49 | if( NOT EXISTS ${FBX_SDK_INSTALL_DIR} ) 50 | message( SEND_ERROR "Provide a valid path to the FBX SDK location (FBX_SDK_INSTALL_DIR)." ) 51 | set( FBX_SDK_DIR FALSE ) 52 | endif() 53 | if( NOT EXISTS ${FBX_SDK_ROOT_DIR} OR NOT FBX_SDK_DIR ) 54 | message( SEND_ERROR "Provide a valid path to the FBX SDK location with correct SDK version (FBX_SDK_VERSION)." ) 55 | set( FBX_SDK_DIR FALSE ) 56 | endif() 57 | if( NOT EXISTS ${FBX_SDK_LIB_ROOT_DIR} ) 58 | message( SEND_ERROR "Provide a valid path to the FBX SDK library directory with correct Visual Studio version (FBX_SDK_VSTUDIO_VERSION)." ) 59 | set( FBX_SDK_DIR FALSE ) 60 | endif() 61 | if( NOT FBX_SDK_DIR ) 62 | return() 63 | endif() 64 | endif() 65 | 66 | set( FBX_SDK_INCLUDE "${FBX_SDK_ROOT_DIR}/include" CACHE PATH "Include directory of the FBX SDK." ) 67 | if( WIN32 ) 68 | set( FBX_SDK_LIB "${FBX_SDK_LIB_ROOT_DIR}/${DZ_PLATFORM}/release/libfbxsdk.lib" CACHE FILEPATH "" ) 69 | set( FBX_SDK_SHARED "${FBX_SDK_LIB_ROOT_DIR}/${DZ_PLATFORM}/release/libfbxsdk.dll" CACHE FILEPATH "" ) 70 | set( FBX_SDK_DEBUG_LIB "${FBX_SDK_LIB_ROOT_DIR}/${DZ_PLATFORM}/debug/libfbxsdk.lib" CACHE FILEPATH "" ) 71 | set( FBX_SDK_DEBUG_SHARED "${FBX_SDK_LIB_ROOT_DIR}/${DZ_PLATFORM}/debug/libfbxsdk.dll" CACHE FILEPATH "" ) 72 | else() 73 | set( FBX_SDK_LIB "${FBX_SDK_ROOT_DIR}/libmac/gcc4/ub/debug/shared/libfbxsdk.dylib" CACHE FILEPATH "" ) 74 | set( FBX_SDK_SHARED "${FBX_SDK_LIB}" CACHE FILEPATH "" ) 75 | set( FBX_SDK_DEBUG_LIB "${FBX_SDK_ROOT_DIR}/libmac/gcc4/ub/release/shared/libfbxsdk.dylib" CACHE FILEPATH "" ) 76 | set( FBX_SDK_DEBUG_SHARED "${FBX_SDK_DEBUG_LIB}" CACHE FILEPATH "" ) 77 | endif( WIN32 ) 78 | 79 | set( FBX_LIB_EXISTS TRUE ) 80 | if( NOT ( EXISTS ${FBX_SDK_INCLUDE} ) ) 81 | message( SEND_ERROR "Invalid path to the FBX SDK include directory (FBX_SDK_INCLUDE)." ) 82 | set( FBX_LIB_EXISTS FALSE ) 83 | endif() 84 | if( NOT ( EXISTS ${FBX_SDK_LIB} ) ) 85 | message( SEND_ERROR "Unable to find the file ${FBX_SDK_LIB} (FBX_SDK_LIB)." ) 86 | set( FBX_LIB_EXISTS FALSE ) 87 | endif() 88 | if( NOT ( EXISTS ${FBX_SDK_SHARED} ) ) 89 | message( SEND_ERROR "Unable to find the file ${FBX_SDK_SHARED} (FBX_SDK_SHARED)." ) 90 | set( FBX_LIB_EXISTS FALSE ) 91 | endif() 92 | if( NOT ( EXISTS ${FBX_SDK_DEBUG_LIB} ) ) 93 | message( SEND_ERROR "Unable to find the file ${FBX_SDK_DEBUG_LIB} (FBX_SDK_DEBUG_LIB)." ) 94 | set( FBX_LIB_EXISTS FALSE ) 95 | endif() 96 | if( NOT ( EXISTS ${FBX_SDK_DEBUG_SHARED} ) ) 97 | message( SEND_ERROR "Unable to find the file ${FBX_SDK_DEBUG_SHARED} (FBX_SDK_DEBUG_SHARED)." ) 98 | set( FBX_LIB_EXISTS FALSE ) 99 | endif() 100 | if( NOT FBX_LIB_EXISTS ) 101 | return() 102 | endif() 103 | 104 | add_library( DzFbx SHARED IMPORTED ) 105 | set_property( TARGET DzFbx APPEND PROPERTY IMPORTED_LOCATION "${FBX_SDK_SHARED}" ) 106 | set_property( TARGET DzFbx APPEND PROPERTY IMPORTED_LOCATION_DEBUG "${FBX_SDK_DEBUG_SHARED}" ) 107 | if( WIN32 ) 108 | set_property( TARGET DzFbx APPEND PROPERTY IMPORTED_IMPLIB "${FBX_SDK_LIB}" ) 109 | set_property( TARGET DzFbx APPEND PROPERTY IMPORTED_IMPLIB_DEBUG "${FBX_SDK_DEBUG_LIB}" ) 110 | endif( WIN32 ) 111 | set_property( TARGET DzFbx APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${FBX_SDK_INCLUDE}" ) 112 | # FBX requires this to be defined when linking dynamically. 113 | set_property( TARGET DzFbx APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS FBXSDK_SHARED ) 114 | 115 | add_library( ${DZ_PLUGIN_TGT_NAME} SHARED 116 | dzfbximporter.cpp 117 | dzfbximporter.h 118 | pluginmain.cpp 119 | version.h 120 | ${OS_SOURCES} 121 | ${PLUGIN_MOC_SOURCES} 122 | ) 123 | 124 | target_link_libraries( ${DZ_PLUGIN_TGT_NAME} 125 | PRIVATE 126 | dzcore 127 | DzFbx 128 | ${DZSDK_QT_CORE_TARGET} 129 | ${DZSDK_QT_GUI_TARGET} 130 | ${DZSDK_QT_SCRIPT_TARGET} 131 | ) 132 | 133 | target_include_directories( ${DZ_PLUGIN_TGT_NAME} 134 | PRIVATE 135 | ${CMAKE_CURRENT_SOURCE_DIR} 136 | ) 137 | 138 | set_target_properties( ${DZ_PLUGIN_TGT_NAME} 139 | PROPERTIES 140 | FOLDER "My Plugins/Importers" 141 | PROJECT_LABEL ${DZ_PLUGIN_PROJECT_NAME} 142 | ) 143 | 144 | setup_standard_plugin_source_groups() 145 | 146 | if( WIN32 ) 147 | target_compile_definitions( ${DZ_PLUGIN_TGT_NAME} PRIVATE -D_CRT_SECURE_NO_DEPRECATE ) 148 | endif() 149 | -------------------------------------------------------------------------------- /FBX Importer/DzFbxImporter.h: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | Copyright (C) 2012-2022 DAZ 3D, Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | **********************************************************************/ 16 | 17 | #pragma once 18 | 19 | /**************************** 20 | Include files 21 | ****************************/ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "dzfileio.h" 28 | #include "dzimporter.h" 29 | #include "dzvec3.h" 30 | #include "dzweightmap.h" 31 | 32 | #include 33 | 34 | /**************************** 35 | Forward declarations 36 | ****************************/ 37 | 38 | class QComboBox; 39 | 40 | class DzFacetMesh; 41 | class DzFacetShape; 42 | class DzFigure; 43 | class DzFloatProperty; 44 | class DzMaterial; 45 | class DzNode; 46 | class DzObject; 47 | class DzSkeleton; 48 | class DzTexture; 49 | 50 | /**************************** 51 | Class definitions 52 | ****************************/ 53 | 54 | class DzFbxImporter : public DzImporter { 55 | Q_OBJECT 56 | public: 57 | DzFbxImporter(); 58 | virtual ~DzFbxImporter(); 59 | 60 | // 61 | // RE-IMPLEMENTATIONS 62 | // 63 | 64 | //////////////////// 65 | //from DzFileIO 66 | virtual void getDefaultOptions( DzFileIOSettings* options ) const; 67 | 68 | //////////////////// 69 | //from DzImporter 70 | virtual bool recognize( const QString &filename ) const; 71 | virtual int getNumExtensions() const; 72 | virtual QString getExtension( int i ) const; 73 | virtual QString getDescription() const; 74 | 75 | virtual DzError read( const QString &filename, const DzFileIOSettings* options ); 76 | 77 | // 78 | // IMPLEMENTATIONS 79 | // 80 | 81 | QString getFileVersion() const; 82 | QString getFileCreator() const; 83 | QString getFileFormat() const; 84 | 85 | QString getSceneAuthor() const; 86 | QString getSceneTitle() const; 87 | QString getSceneSubject() const; 88 | QString getSceneKeywords() const; 89 | QString getSceneRevision() const; 90 | QString getSceneComment() const; 91 | QString getOriginalAppVendor() const; 92 | QString getOriginalAppName() const; 93 | QString getOriginalAppVersion() const; 94 | 95 | QStringList getAnimStackNames() const; 96 | QStringList getErrorList() const; 97 | 98 | public slots: 99 | 100 | void setRotationLimits( bool enable ); 101 | void setIncludeAnimations( bool enable ); 102 | void setTakeName( const QString &name ); 103 | 104 | void setIncludePolygonSets( bool enable ); 105 | void setIncludePolygonGroups( bool enable ); 106 | 107 | void setStudioNodeNamesLabels( bool enable ); 108 | void setStudioNodePresentation( bool enable ); 109 | void setStudioNodeSelectionMap( bool enable ); 110 | void setStudioSceneIDs( bool enable ); 111 | 112 | protected: 113 | 114 | int getOptions( DzFileIOSettings* options, const DzFileIOSettings* impOptions, const QString &filename ); 115 | 116 | private: 117 | 118 | class Node { 119 | public: 120 | Node() : 121 | parent( 0 ), 122 | dsParent( 0 ), 123 | dsNode( 0 ), 124 | fbxNode( 0 ), 125 | bindTranslation( 0, 0, 0 ), 126 | collapseTranslation( false ) 127 | {} 128 | 129 | void setParent( Node* parent ) 130 | { 131 | this->parent = parent; 132 | if ( this->parent ) 133 | { 134 | this->parent->children.append( this ); 135 | } 136 | } 137 | 138 | Node* find( DzNode* inDazNode ) 139 | { 140 | if ( !inDazNode ) 141 | { 142 | return NULL; 143 | } 144 | 145 | if ( dsNode == inDazNode ) 146 | { 147 | return this; 148 | } 149 | 150 | for ( int i = 0; i < children.count(); i++ ) 151 | { 152 | Node* child = children[i]->find( inDazNode ); 153 | if ( child ) 154 | { 155 | return child; 156 | } 157 | } 158 | 159 | return NULL; 160 | } 161 | 162 | Node* parent; 163 | QVector children; 164 | DzNode* dsParent; 165 | DzNode* dsNode; 166 | FbxNode* fbxNode; 167 | DzVec3 bindTranslation; 168 | bool collapseTranslation; 169 | }; 170 | 171 | struct Skinning 172 | { 173 | Node* node; 174 | FbxSkin* fbxSkin; 175 | DzFigure* dsFigure; 176 | int numVertices; 177 | DzWeightMapPtr blendWeights; 178 | }; 179 | 180 | 181 | void fbxPreImportAnimationStack(); 182 | void fbxPreImportGraph( FbxNode* fbxNode ); 183 | void fbxPreImport(); 184 | 185 | DzTexture* toTexture( FbxProperty fbxProperty ); 186 | 187 | void fbxImportVertices( int numVertices, FbxVector4* fbxVertices, DzFacetMesh* dsMesh, DzVec3 offset ); 188 | void fbxImportUVs( FbxMesh* fbxMesh, DzFacetMesh* dsMesh ); 189 | void fbxImportSubdVertexWeights( FbxMesh* fbxMesh, DzFacetMesh* dsMesh, bool &enableSubd ); 190 | void fbxImportMaterials( FbxNode* fbxNode, FbxMesh* fbxMesh, DzFacetMesh* dsMesh, DzFacetShape* dsShape, bool &matsAllSame ); 191 | void fbxImportPolygonSets( DzNode* dsMeshNode, DzFacetMesh* dsMesh, DzFacetShape* dsShape ); 192 | void fbxImportFaces( FbxMesh* fbxMesh, DzFacetMesh* dsMesh, bool matsAllSame, QMap, int> &edgeMap ); 193 | void fbxImportSubdEdgeWeights( FbxMesh* fbxMesh, DzFacetMesh* dsMesh, QMap, int> edgeMap, bool &enableSubd ); 194 | DzWeightMapPtr fbxImportSkinningBlendWeights( int numVertices, const FbxSkin* fbxSkin ); 195 | void fbxImportMorph( FbxBlendShape* fbxBlendShape, DzObject* dsObject, int numVertices, FbxVector4* fbxVertices ); 196 | void fbxImportMeshModifiers( Node* node, FbxMesh* fbxMesh, DzObject* dsObject, DzFigure* dsFigure, int numVertices, FbxVector4* fbxVertices ); 197 | void fbxImportMesh( Node* node, FbxNode* fbxNode, DzNode* dsMeshNode ); 198 | void setSubdEnabled( bool onOff, DzFacetMesh* dsMesh, DzFacetShape* dsShape ); 199 | 200 | void applyFbxCurve( FbxAnimCurve* fbxCurve, DzFloatProperty* dsProperty, double scale = 1 ); 201 | 202 | void fbxImportGraph( Node* node ); 203 | void fbxImportAnimation( Node* node ); 204 | 205 | void updateSelectionMap( Node* node ); 206 | 207 | void replicateSkeleton( DzSkeleton* dsBaseSkeleton, const Skinning &skinning ); 208 | 209 | void fbxRead( const QString &filename ); 210 | void fbxPickAnimationTake( int idx ); 211 | void fbxPickAnimation(); 212 | void fbxImportSkinning(); 213 | void fbxImport(); 214 | void fbxCleanup(); 215 | 216 | 217 | bool m_fbxRead; 218 | FbxManager* m_fbxManager; 219 | FbxScene* m_fbxScene; 220 | 221 | QStringList m_animStackNames; 222 | FbxAnimStack* m_fbxAnimStack; 223 | FbxAnimLayer* m_fbxAnimLayer; 224 | 225 | int m_fbxFileMajor; 226 | int m_fbxFileMinor; 227 | int m_fbxFileRevision; 228 | FbxString m_fbxFileCreator; 229 | int m_fbxFileBinary; 230 | 231 | FbxString m_fbxSceneAuthor; 232 | FbxString m_fbxSceneTitle; 233 | FbxString m_fbxSceneSubject; 234 | FbxString m_fbxSceneKeywords; 235 | FbxString m_fbxSceneRevision; 236 | FbxString m_fbxSceneComment; 237 | FbxString m_fbxOrigAppVendor; 238 | FbxString m_fbxOrigAppName; 239 | FbxString m_fbxOrigAppVersion; 240 | 241 | QVector m_skins; 242 | QMap m_nodeMap; 243 | QMap m_nodeFaceGroupMap; 244 | bool m_needConversion; 245 | DzTime m_dsEndTime; 246 | 247 | bool m_suppressRigErrors; 248 | QStringList m_errorList; 249 | 250 | QDir m_folder; 251 | 252 | QVector m_dsMaterials; 253 | 254 | bool m_includeRotationLimits; 255 | bool m_includeAnimations; 256 | QString m_takeName; 257 | 258 | bool m_includePolygonSets; 259 | bool m_includePolygonGroups; 260 | 261 | bool m_studioNodeNamesLabels; 262 | bool m_studioNodePresentation; 263 | bool m_studioNodeSelectionMap; 264 | bool m_studioSceneIDs; 265 | 266 | Node* m_root; 267 | }; 268 | 269 | 270 | class DzFbxImportFrame : public DzFileIOFrame { 271 | Q_OBJECT 272 | public: 273 | DzFbxImportFrame( DzFbxImporter* importer ); 274 | ~DzFbxImportFrame(); 275 | 276 | // 277 | // RE-IMPLEMENTATIONS 278 | // 279 | 280 | //////////////////// 281 | //from DzFileIOFrame 282 | virtual void setOptions( const DzFileIOSettings* settings, const QString &filename ); 283 | virtual void getOptions( DzFileIOSettings* settings ) const; 284 | 285 | protected: 286 | 287 | //////////////////// 288 | //from DzOptionsFrame 289 | virtual void applyChanges(); 290 | virtual void resetOptions(); 291 | 292 | private: 293 | 294 | struct Data; 295 | QScopedPointer m_data; 296 | }; 297 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /FBX Importer/DzFbxImporter.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | Copyright (C) 2012-2022 DAZ 3D, Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | **********************************************************************/ 16 | #include "dzversion.h" 17 | 18 | #if ((DZ_SDK_VERSION_MAJOR >= 5) || ((DZ_SDK_VERSION_MAJOR == 4) && (DZ_SDK_VERSION_MINOR >= 12))) 19 | #define DZ_SDK_4_12_OR_GREATER 1 20 | #else 21 | #define DZ_SDK_4_12_OR_GREATER 0 22 | #endif 23 | 24 | /***************************** 25 | Include files 26 | *****************************/ 27 | // Direct Relation 28 | #include "DzFbxImporter.h" 29 | 30 | // System 31 | 32 | // Standard Library 33 | 34 | // Qt 35 | #include 36 | 37 | // DS Public SDK 38 | #include "dzapp.h" 39 | #include "dzbone.h" 40 | #include "dzbonebinding.h" 41 | #if DZ_SDK_4_12_OR_GREATER 42 | #include "dzcollapsiblegroupbox.h" 43 | #endif //DZ_SDK_4_12_OR_GREATER 44 | #include "dzdefaultmaterial.h" 45 | #include "dzenumproperty.h" 46 | #include "dzfacegroup.h" 47 | #include "dzfacetmesh.h" 48 | #include "dzfacetshape.h" 49 | #include "dzfigure.h" 50 | #include "dzfileiosettings.h" 51 | #include "dzfloatproperty.h" 52 | #if DZ_SDK_4_12_OR_GREATER 53 | #include "dzgraftingfigureshape.h" 54 | #endif // DZ_SDK_4_12_OR_GREATER 55 | #include "dzdynamicdividerwgt.h" 56 | #include "dzimagemgr.h" 57 | #include "dzmorph.h" 58 | #include "dzmorphdeltas.h" 59 | #include "dznode.h" 60 | #include "dzobject.h" 61 | #include "dzpresentation.h" 62 | #include "dzprogress.h" 63 | #include "dzscene.h" 64 | #include "dzselectionmap.h" 65 | #include "dzsettings.h" 66 | #include "dzskinbinding.h" 67 | #include "dzstyle.h" 68 | 69 | // Project Specific 70 | 71 | /***************************** 72 | Local Definitions 73 | *****************************/ 74 | 75 | #if FBXSDK_VERSION_MAJOR >= 2016 76 | #define DATA_FBX_USER_PROPERTIES "FbxUserProperties" 77 | #define DATA_LOD_INFO "LODInfo" 78 | #endif 79 | 80 | namespace 81 | { 82 | 83 | // settings keys 84 | const QString c_optTake( "Take" ); 85 | 86 | const QString c_optIncRotationLimits( "IncludeRotationLimits" ); 87 | const QString c_optIncAnimations( "IncludeAnimations" ); 88 | 89 | const QString c_optIncPolygonSets( "IncludePolygonSets" ); 90 | const QString c_optIncPolygonGroups( "IncludePolygonGroups" ); 91 | 92 | const QString c_optStudioNodeNamesLabels( "IncludeNodeNamesLabels" ); 93 | const QString c_optStudioPresentation( "IncludeNodePresentation" ); 94 | const QString c_optStudioNodeSelectionMap( "IncludeNodeSelectionMap" ); 95 | const QString c_optStudioSceneIDs( "IncludeSceneIDs" ); 96 | 97 | const QString c_optRunSilent( "RunSilent" ); 98 | 99 | // settings default values 100 | const bool c_defaultIncludeRotationLimits = true; 101 | const bool c_defaultIncludeAnimations = false; 102 | 103 | const bool c_defaultIncludePolygonSets = true; 104 | const bool c_defaultIncludePolygonGroups = false; 105 | 106 | const bool c_defaultStudioNodeNames = true; 107 | const bool c_defaultStudioNodePresentation = true; 108 | const bool c_defaultStudioNodeSelectionMap = true; 109 | const bool c_defaultStudioSceneIDs = true; 110 | 111 | // functions 112 | DzFigure* createFigure() 113 | { 114 | DzFigure* dsFigure = new DzFigure(); 115 | 116 | DzEnumProperty* followModeControl = NULL; 117 | #if DZ_SDK_4_12_OR_GREATER 118 | followModeControl = dsFigure->getFollowModeControl(); 119 | followModeControl->setValue( DzSkeleton::fmAutoFollow ); 120 | #else 121 | // DzSkeleton::getFollowModeControl() is not in the 4.5 SDK, so we attempt 122 | // to use the meta-object to call the methods - since 4.8.0.23. If this fails, 123 | // we attempt to find the property by name and if found set its value. 124 | 125 | if ( !QMetaObject::invokeMethod( dsFigure, 126 | "getFollowModeControl", Q_RETURN_ARG( DzEnumProperty*, followModeControl ) ) 127 | || !followModeControl ) 128 | { 129 | followModeControl = qobject_cast( dsFigure->findProperty( "Fit to Mode" ) ); 130 | if ( followModeControl ) 131 | { 132 | followModeControl->setValue( 1 ); 133 | } 134 | } 135 | #endif 136 | 137 | dsFigure->setDrawGLBones( true ); 138 | 139 | return dsFigure; 140 | } 141 | 142 | } // namespace 143 | 144 | /////////////////////////////////////////////////////////////////////// 145 | // DzFbxImporter 146 | /////////////////////////////////////////////////////////////////////// 147 | 148 | #ifdef DAZ_SCRIPT_DOCS 149 | 150 | class DzFbxImporter : public DzImporter { 151 | public: 152 | // DAZScript Constructors 153 | 154 | DzFbxImporter(); 155 | }; 156 | 157 | #endif // DAZ_SCRIPT_DOCS 158 | 159 | /** 160 | @script 161 | @class DzFbxImporter 162 | 163 | @ingroup FileIO 164 | @nosubgrouping 165 | @brief Class for importing files in the Autodesk FBX (*.fbx) format. 166 | 167 | A specialization of DzImporter that implements an importer for the Autodesk 168 | FBX (.fbx) format. Through its use of the FBX SDK to accomplish this task, 169 | this importer also provides import capabilities for the Autodesk AutoCAD DXF 170 | (.dxf) format, the Autodesk 3ds Max (.3ds) format, and the Collada DAE (.dae) 171 | format, as supported by the FBX SDK. 172 | 173 | @attention The FBX SDK also provides import capabilities for the Alias 174 | Wavefront OBJ (.obj) format, but it has been intentionally 175 | excluded. Use DzObjImporter instead. 176 | 177 | @sa DzImportMgr::findImporterByClassName() 178 | @sa DzImportMgr::findImporter() 179 | 180 | @sa Sample: @dzscript{api_reference/samples/file_io/import_fbx_silent/start, Silent FBX Import} 181 | **/ 182 | 183 | 184 | /** 185 | @script 186 | Default Constructor. 187 | **/ 188 | DzFbxImporter::DzFbxImporter() : 189 | m_fbxRead( false ), 190 | m_fbxManager( NULL ), 191 | m_fbxScene( NULL ), 192 | m_fbxAnimStack( NULL ), 193 | m_fbxAnimLayer( NULL ), 194 | m_fbxFileMajor( 0 ), 195 | m_fbxFileMinor( 0 ), 196 | m_fbxFileRevision( 0 ), 197 | m_fbxFileBinary( -1 ), 198 | m_needConversion( false ), 199 | m_dsEndTime( 0 ), 200 | m_suppressRigErrors( false ), 201 | m_includeRotationLimits( c_defaultIncludeRotationLimits ), 202 | m_includeAnimations( c_defaultIncludeAnimations ), 203 | m_includePolygonSets( c_defaultIncludePolygonSets ), 204 | m_includePolygonGroups( c_defaultIncludePolygonGroups ), 205 | m_studioNodeNamesLabels( c_defaultStudioNodeNames ), 206 | m_studioNodePresentation( c_defaultStudioNodePresentation ), 207 | m_studioNodeSelectionMap( c_defaultStudioNodeSelectionMap ), 208 | m_studioSceneIDs( c_defaultStudioSceneIDs ), 209 | m_root( NULL ) 210 | {} 211 | 212 | /** 213 | **/ 214 | DzFbxImporter::~DzFbxImporter() 215 | { 216 | } 217 | 218 | /** 219 | **/ 220 | bool DzFbxImporter::recognize( const QString &filename ) const 221 | { 222 | const QString ext = getFileExtension( filename ); //return value is lowercase 223 | for ( int i = 0, n = getNumExtensions(); i < n; i++ ) 224 | { 225 | if ( ext == getExtension( i ) ) 226 | { 227 | return true; 228 | } 229 | } 230 | 231 | return false; 232 | } 233 | 234 | /** 235 | **/ 236 | int DzFbxImporter::getNumExtensions() const 237 | { 238 | return 4; 239 | } 240 | 241 | /** 242 | **/ 243 | QString DzFbxImporter::getExtension( int i ) const 244 | { 245 | switch ( i ) 246 | { 247 | case 0: 248 | return "fbx"; 249 | case 1: 250 | return "dxf"; 251 | case 2: 252 | return "3ds"; 253 | case 3: 254 | // DzCOLLADAImporter depends on FCollada (discontinued) 255 | // DzCOLLADAImporter is deprecated 256 | return "dae"; 257 | case 4: 258 | // DzObjImporter provides a more suitable result 259 | // This conflicts with DzObjImporter and recognize() 260 | //return "obj"; 261 | default: 262 | return QString(); 263 | } 264 | } 265 | 266 | /** 267 | **/ 268 | QString DzFbxImporter::getDescription() const 269 | { 270 | return "Autodesk FBX SDK"; 271 | } 272 | 273 | /** 274 | **/ 275 | void DzFbxImporter::getDefaultOptions( DzFileIOSettings* options ) const 276 | { 277 | assert( options ); 278 | if ( !options ) 279 | { 280 | return; 281 | } 282 | 283 | // Properties 284 | options->setBoolValue( c_optIncRotationLimits, c_defaultIncludeRotationLimits ); 285 | options->setBoolValue( c_optIncAnimations, c_defaultIncludeAnimations ); 286 | options->setStringValue( c_optTake, QString() ); 287 | 288 | // Geometry 289 | options->setBoolValue( c_optIncPolygonSets, c_defaultIncludePolygonSets ); 290 | options->setBoolValue( c_optIncPolygonGroups, c_defaultIncludePolygonGroups ); 291 | 292 | // Custom Data 293 | options->setBoolValue( c_optStudioNodeNamesLabels, c_defaultStudioNodeNames ); 294 | options->setBoolValue( c_optStudioPresentation, c_defaultStudioNodePresentation ); 295 | options->setBoolValue( c_optStudioNodeSelectionMap, c_defaultStudioNodeSelectionMap ); 296 | options->setBoolValue( c_optStudioSceneIDs, c_defaultStudioSceneIDs ); 297 | 298 | options->setIntValue( c_optRunSilent, 0 ); 299 | } 300 | 301 | 302 | namespace 303 | { 304 | 305 | class MapConversion { 306 | public: 307 | QVector fbxWeights; 308 | unsigned short* dsWeights; 309 | }; 310 | 311 | bool isChildNode( DzNode* child, DzNode* parent ) 312 | { 313 | if ( !parent || !child || child == parent ) 314 | { 315 | return false; 316 | } 317 | 318 | while ( child ) 319 | { 320 | if ( child == parent ) 321 | { 322 | return true; 323 | } 324 | child = child->getNodeParent(); 325 | } 326 | 327 | return false; 328 | } 329 | 330 | } //namespace 331 | 332 | /** 333 | Manually get the options. If the "RunSilent" option is true, then the dialog 334 | will be skipped. 335 | **/ 336 | int DzFbxImporter::getOptions( DzFileIOSettings* options, const DzFileIOSettings* impOptions, const QString &filename ) 337 | { 338 | assert( options ); 339 | assert( impOptions ); 340 | if ( !options || !impOptions ) 341 | { 342 | return false; 343 | } 344 | 345 | bool optionsShown = false; 346 | #if DZ_SDK_4_12_OR_GREATER 347 | optionsShown = getOptionsShown(); 348 | #endif 349 | 350 | if ( optionsShown || impOptions->getIntValue( c_optRunSilent, 0 ) ) 351 | { 352 | if ( optionsShown ) 353 | { 354 | getSavedOptions( options ); // includes defaults 355 | } 356 | else 357 | { 358 | getDefaultOptions( options ); 359 | } 360 | 361 | #if DZ_SDK_4_12_OR_GREATER 362 | copySettings( options, impOptions ); 363 | #else 364 | // DzFileIO::copySettings() is not in the 4.5 SDK, and it is not exposed 365 | // to QMetaObject::invokedMethod() in later builds, so we copy manually. 366 | for ( int i = 0, n = options->getNumValues(); i < n; i++ ) 367 | { 368 | const QString key = options->getKey( i ); 369 | switch ( options->getValueType( i ) ) 370 | { 371 | default: 372 | case DzSettings::StringValue: 373 | case DzSettings::IntValue: 374 | case DzSettings::BoolValue: 375 | case DzSettings::FloatValue: 376 | impOptions->copySetting( key, options ); 377 | break; 378 | case DzSettings::SettingsValue: 379 | impOptions->copySetting( key, options->getSettingsValue( key ) ); 380 | break; 381 | } 382 | } 383 | #endif 384 | 385 | return true; 386 | } 387 | 388 | fbxRead( filename ); 389 | fbxPreImport(); 390 | 391 | DzFbxImporter* self = const_cast( this ); 392 | DzFbxImportFrame* frame = new DzFbxImportFrame( self ); 393 | if ( !frame ) 394 | { 395 | fbxCleanup(); 396 | return true; 397 | } 398 | 399 | DzFileIODlg optionsDlg( frame ); 400 | frame->setOptions( impOptions, filename ); 401 | if ( optionsDlg.exec() != QDialog::Accepted ) 402 | { 403 | fbxCleanup(); 404 | return false; // user cancelled 405 | } 406 | 407 | #if DZ_SDK_4_12_OR_GREATER 408 | setOptionsShown( true ); 409 | #endif 410 | 411 | frame->getOptions( options ); 412 | 413 | // if handling the options dialog ourselves, we also need to save the state 414 | options->setIntValue( c_optRunSilent, 0 ); 415 | saveOptions( options ); 416 | 417 | return true; 418 | } 419 | 420 | /** 421 | **/ 422 | void DzFbxImporter::fbxRead( const QString &filename ) 423 | { 424 | if ( m_fbxRead ) 425 | { 426 | return; 427 | } 428 | 429 | QString orgName; 430 | #if DZ_SDK_4_12_OR_GREATER 431 | orgName = dzApp->getOrgName(); 432 | #else 433 | // DzApp::getOrgName() is not in the 4.5 SDK, so we attempt to use the 434 | // meta-object to access the DzApp::orgName property - since 4.6.4.30. 435 | 436 | orgName = dzApp->property( "orgName" ).toString(); 437 | #endif 438 | if ( !orgName.isEmpty() 439 | && orgName != QString( "DAZ 3D" ) ) 440 | { 441 | m_suppressRigErrors = true; 442 | } 443 | 444 | m_fbxManager = FbxManager::Create(); 445 | FbxIOSettings* fbxIoSettings = FbxIOSettings::Create( m_fbxManager, IOSROOT ); 446 | m_fbxManager->SetIOSettings( fbxIoSettings ); 447 | 448 | m_fbxScene = FbxScene::Create( m_fbxManager, "" ); 449 | 450 | m_fbxAnimStack = NULL; 451 | m_fbxAnimLayer = NULL; 452 | m_dsEndTime = dzScene->getAnimRange().getEnd(); 453 | 454 | FbxImporter* fbxImporter = FbxImporter::Create( m_fbxManager, "" ); 455 | if ( !fbxImporter->Initialize( filename.toUtf8().data(), -1, fbxIoSettings ) ) 456 | { 457 | const FbxStatus status = fbxImporter->GetStatus(); 458 | if ( status != FbxStatus::eSuccess ) 459 | { 460 | dzApp->warning( QString( "FBX Importer: %1" ).arg( status.GetErrorString() ) ); 461 | } 462 | } 463 | 464 | fbxImporter->GetFileVersion( m_fbxFileMajor, m_fbxFileMinor, m_fbxFileRevision ); 465 | 466 | if ( fbxImporter->IsFBX() ) 467 | { 468 | fbxIoSettings->SetBoolProp( IMP_FBX_MATERIAL, true ); 469 | fbxIoSettings->SetBoolProp( IMP_FBX_TEXTURE, true ); 470 | fbxIoSettings->SetBoolProp( IMP_FBX_LINK, true ); 471 | fbxIoSettings->SetBoolProp( IMP_FBX_SHAPE, true ); 472 | fbxIoSettings->SetBoolProp( IMP_FBX_GOBO, true ); 473 | fbxIoSettings->SetBoolProp( IMP_FBX_ANIMATION, true ); 474 | fbxIoSettings->SetBoolProp( IMP_FBX_GLOBAL_SETTINGS, true ); 475 | } 476 | 477 | #if FBXSDK_VERSION_MAJOR >= 2020 478 | fbxImporter->GetStatus().KeepErrorStringHistory( true ); 479 | #endif 480 | 481 | fbxImporter->Import( m_fbxScene ); 482 | 483 | FbxStatus status = fbxImporter->GetStatus(); 484 | if ( status != FbxStatus::eSuccess ) 485 | { 486 | #if FBXSDK_VERSION_MAJOR >= 2020 487 | FbxArray history; 488 | status.GetErrorStringHistory( history ); 489 | if ( history.GetCount() > 1 ) 490 | { 491 | // error strings are in stack order (last error -> first element) 492 | for ( int i = history.GetCount() - 1; i >= 0 ; --i ) 493 | { 494 | dzApp->warning( QString( "FBX Importer: %1" ).arg( history[i]->Buffer() ) ); 495 | } 496 | } 497 | FbxArrayDelete( history ); 498 | #else 499 | dzApp->warning( QString( "FBX Importer: %1" ).arg( status.GetErrorString() ) ); 500 | #endif 501 | } 502 | 503 | const FbxIOFileHeaderInfo* fbxHeaderInfo = fbxImporter->GetFileHeaderInfo(); 504 | m_fbxFileCreator = fbxHeaderInfo->mCreator; 505 | #if FBXSDK_VERSION_MAJOR > 2020 || (FBXSDK_VERSION_MAJOR == 2020 && FBXSDK_VERSION_MINOR >= 3) 506 | m_fbxFileBinary = fbxHeaderInfo->mBinary ? 1 : 0; 507 | #endif 508 | 509 | fbxImporter->Destroy(); 510 | 511 | const FbxDocumentInfo* fbxSceneInfo = m_fbxScene->GetSceneInfo(); 512 | m_fbxSceneAuthor = fbxSceneInfo->mAuthor; 513 | m_fbxSceneTitle = fbxSceneInfo->mTitle; 514 | m_fbxSceneSubject = fbxSceneInfo->mSubject; 515 | m_fbxSceneKeywords = fbxSceneInfo->mKeywords; 516 | m_fbxSceneRevision = fbxSceneInfo->mRevision; 517 | m_fbxSceneComment = fbxSceneInfo->mComment; 518 | m_fbxOrigAppVendor = fbxSceneInfo->Original_ApplicationVendor; 519 | m_fbxOrigAppName = fbxSceneInfo->Original_ApplicationName; 520 | m_fbxOrigAppVersion = fbxSceneInfo->Original_ApplicationVersion; 521 | 522 | m_fbxRead = true; 523 | } 524 | 525 | /** 526 | **/ 527 | void DzFbxImporter::fbxPickAnimationTake( int idx ) 528 | { 529 | m_fbxAnimStack = m_fbxScene->GetSrcObject( idx ); 530 | if ( m_fbxAnimStack->GetMemberCount() <= 0 ) 531 | { 532 | return; 533 | } 534 | 535 | m_fbxAnimLayer = m_fbxAnimStack->GetMember( 0 ); 536 | } 537 | 538 | /** 539 | **/ 540 | void DzFbxImporter::fbxPickAnimation() 541 | { 542 | if ( !m_includeAnimations 543 | || m_takeName.isEmpty() ) 544 | { 545 | return; 546 | } 547 | 548 | const QString idxPrefix( "idx::" ); 549 | if ( m_takeName.startsWith( idxPrefix ) ) 550 | { 551 | bool isNum = false; 552 | const int takeIdx = m_takeName.mid( idxPrefix.length() ).toInt( &isNum ); 553 | if ( isNum 554 | && takeIdx > -1 555 | && takeIdx < m_fbxScene->GetSrcObjectCount() ) 556 | { 557 | fbxPickAnimationTake( takeIdx ); 558 | } 559 | } 560 | else 561 | { 562 | for ( int i = 0, n = m_fbxScene->GetSrcObjectCount(); i < n; i++ ) 563 | { 564 | const FbxAnimStack* animStack = m_fbxScene->GetSrcObject( i ); 565 | if ( QString( animStack->GetName() ) != m_takeName ) 566 | { 567 | continue; 568 | } 569 | 570 | fbxPickAnimationTake( i ); 571 | } 572 | } 573 | } 574 | 575 | /** 576 | **/ 577 | void DzFbxImporter::fbxImportSkinning() 578 | { 579 | QVector dsBones; 580 | for ( int i = 0; i < m_skins.size(); i++ ) 581 | { 582 | Skinning skinning = m_skins[i]; 583 | 584 | const Node* node = skinning.node; 585 | Q_UNUSED( node ) 586 | 587 | FbxSkin* fbxSkin = skinning.fbxSkin; 588 | DzFigure* dsFigure = skinning.dsFigure; 589 | const int numVertices = skinning.numVertices; 590 | 591 | DzSkinBinding* dsSkin = dsFigure->getSkinBinding(); 592 | 593 | #if DZ_SDK_4_12_OR_GREATER 594 | if ( dsSkin 595 | && dsSkin->getTargetVertexCount() < 1 ) 596 | { 597 | dsSkin->setTargetVertexCount( numVertices ); 598 | #else 599 | // DzSkinBinding::getTargetVertexCount() is not in the 4.5 SDK, so 600 | // we attempt to use the meta-object to call the method. 601 | 602 | int targetVertexCount = 0; 603 | if ( dsSkin 604 | && QMetaObject::invokeMethod( dsSkin, "getTargetVertexCount", 605 | Q_RETURN_ARG( int, targetVertexCount ) ) 606 | && targetVertexCount < 1 ) 607 | { 608 | // DzSkinBinding::setTargetVertexCount() is not in the 4.5 SDK, 609 | // so we attempt to use the meta-object to call the method. 610 | 611 | bool im = QMetaObject::invokeMethod( dsSkin, "setTargetVertexCount", 612 | Q_ARG( int, numVertices ) ); 613 | assert( im ); 614 | #endif 615 | } 616 | else if ( !dsSkin ) 617 | { 618 | assert( !"Binding was not found" ); 619 | continue; 620 | } 621 | 622 | const int numClusters = fbxSkin->GetClusterCount(); 623 | 624 | DzSkeleton* dsBaseSkeleton = NULL; 625 | 626 | for ( int j = 0; j < numClusters; j++ ) 627 | { 628 | FbxCluster* fbxCluster = fbxSkin->GetCluster( j ); 629 | DzBone* dsBone = qobject_cast( m_nodeMap.value( fbxCluster->GetLink() ) ); 630 | if ( !dsBone ) 631 | { 632 | continue; 633 | } 634 | 635 | if ( !isChildNode( dsBone, dsFigure ) ) 636 | { 637 | dsBaseSkeleton = dsBone->getSkeleton(); 638 | } 639 | } 640 | 641 | if ( dsBaseSkeleton ) 642 | { 643 | replicateSkeleton( dsBaseSkeleton, skinning ); 644 | } 645 | 646 | 647 | DzWeightMapList maps; 648 | QVector mapConversions; 649 | for ( int j = 0; j < numClusters; j++ ) 650 | { 651 | FbxCluster* fbxCluster = fbxSkin->GetCluster( j ); 652 | DzBone* dsBone = qobject_cast( m_nodeMap.value( fbxCluster->GetLink() ) ); 653 | if ( !dsBone ) 654 | { 655 | continue; 656 | } 657 | 658 | DzBoneBinding* dsBinding = new DzBoneBinding(); 659 | dsBinding->setBone( dsBone ); 660 | dsSkin->addBoneBinding( dsBinding ); 661 | 662 | DzWeightMap* dsWeightMap = new DzWeightMap( numVertices ); 663 | int* fbxIndices = fbxCluster->GetControlPointIndices(); 664 | double* fbxWeights = fbxCluster->GetControlPointWeights(); 665 | 666 | MapConversion mapConv; 667 | mapConv.dsWeights = dsWeightMap->getWeights(); 668 | mapConv.fbxWeights.resize( numVertices ); 669 | for ( int k = 0; k < fbxCluster->GetControlPointIndicesCount(); k++ ) 670 | { 671 | mapConv.fbxWeights[fbxIndices[k]] = fbxWeights[k]; 672 | } 673 | mapConversions.append( mapConv ); 674 | 675 | dsBinding->setWeights( dsWeightMap ); 676 | FbxAMatrix fbxMatrix; 677 | fbxCluster->GetTransformLinkMatrix( fbxMatrix ); 678 | 679 | DzMatrix3 dsMatrix; 680 | dsMatrix[0][0] = fbxMatrix[0][0]; 681 | dsMatrix[0][1] = fbxMatrix[0][1]; 682 | dsMatrix[0][2] = fbxMatrix[0][2]; 683 | dsMatrix[1][0] = fbxMatrix[1][0]; 684 | dsMatrix[1][1] = fbxMatrix[1][1]; 685 | dsMatrix[1][2] = fbxMatrix[1][2]; 686 | dsMatrix[2][0] = fbxMatrix[2][0]; 687 | dsMatrix[2][1] = fbxMatrix[2][1]; 688 | dsMatrix[2][2] = fbxMatrix[2][2]; 689 | dsMatrix[3][0] = -fbxMatrix[3][0]; 690 | dsMatrix[3][1] = -fbxMatrix[3][1]; 691 | dsMatrix[3][2] = -fbxMatrix[3][2]; 692 | 693 | DzVec3 skelOrigin = dsFigure->getOrigin(); 694 | DzVec3 origin = dsBone->getOrigin(); 695 | dsMatrix[3][0] += ( origin[0] - skelOrigin[0] ); 696 | dsMatrix[3][1] += ( origin[1] - skelOrigin[1] ); 697 | dsMatrix[3][2] += ( origin[2] - skelOrigin[2] ); 698 | dsBinding->setBindingMatrix( dsMatrix ); 699 | maps.append( dsWeightMap ); 700 | } 701 | 702 | for ( int v = 0; v < numVertices; v++ ) 703 | { 704 | double sum = 0.0; 705 | for ( int m = 0; m < mapConversions.count(); m++ ) 706 | { 707 | sum += mapConversions[m].fbxWeights[v]; 708 | } 709 | 710 | for ( int m = 0; m < mapConversions.count(); m++ ) 711 | { 712 | mapConversions[m].dsWeights[v] = static_cast( mapConversions[m].fbxWeights[v] / sum * DZ_USHORT_MAX ); 713 | } 714 | } 715 | 716 | DzWeightMap::normalizeMaps( maps ); 717 | 718 | FbxSkin::EType fbxSkinningType = fbxSkin->GetSkinningType(); 719 | 720 | #if DZ_SDK_4_12_OR_GREATER 721 | DzSkinBinding::BindingMode bindingMode = DzSkinBinding::General; 722 | DzSkinBinding::GeneralMapMode generalMapMode = DzSkinBinding::Linear; 723 | switch ( fbxSkinningType ) 724 | { 725 | default: 726 | break; 727 | case FbxSkin::eDualQuaternion: 728 | generalMapMode = DzSkinBinding::DualQuat; 729 | break; 730 | case FbxSkin::eBlend: 731 | bindingMode = DzSkinBinding::Blended; 732 | generalMapMode = DzSkinBinding::DualQuat; 733 | break; 734 | } 735 | 736 | dsSkin->setBindingMode( bindingMode ); 737 | dsSkin->setGeneralMapMode( generalMapMode ); 738 | dsSkin->setScaleMode( DzSkinBinding::BindingMaps ); 739 | 740 | #else 741 | // DzSkinBinding::BindingMode, and DzSkinBinding::GeneralMapMode are not 742 | // in the 4.5 SDK, so we use the int equivalents. 743 | 744 | int bindingMode = 0; 745 | int generalMapMode = 0; 746 | switch ( fbxSkinningType ) 747 | { 748 | default: 749 | break; 750 | case FbxSkin::eDualQuaternion: 751 | generalMapMode = 1; 752 | break; 753 | case FbxSkin::eBlend: 754 | bindingMode = 2; 755 | generalMapMode = 1; 756 | break; 757 | } 758 | 759 | // DzSkinBinding::setBindingMode(), DzSkinBinding::setScaleMode(), 760 | // and DzSkinBinding::setGeneralMapMode() are not in the 4.5 SDK, 761 | // so we attempt to use the meta-object to call these methods. 762 | 763 | bool im = QMetaObject::invokeMethod( dsSkin, "setBindingMode", 764 | Q_ARG( int, bindingMode ) ); 765 | assert( im ); 766 | 767 | im = QMetaObject::invokeMethod( dsSkin, "setGeneralMapMode", 768 | Q_ARG( int, generalMapMode ) ); 769 | assert( im ); 770 | 771 | im = QMetaObject::invokeMethod( dsSkin, "setScaleMode", 772 | Q_ARG( int, 1 ) ); 773 | assert( im ); 774 | #endif 775 | 776 | if ( fbxSkinningType == FbxSkin::eBlend 777 | && skinning.blendWeights ) 778 | { 779 | #if DZ_SDK_4_12_OR_GREATER 780 | dsSkin->setBlendMap( skinning.blendWeights ); 781 | dsSkin->setBlendMode( DzSkinBinding::BlendLinearDualQuat ); 782 | #else 783 | // DzSkinBinding::setBlendMap() and DzSkinBinding::setBlendMode() 784 | // are not in the 4.5 SDK, so we attempt to use the meta-object to 785 | // call these methods. 786 | 787 | im = QMetaObject::invokeMethod( dsSkin, "setBlendMap", 788 | Q_ARG( DzWeightMap*, skinning.blendWeights.operator->() ) ); 789 | assert( im ); 790 | 791 | im = QMetaObject::invokeMethod( dsSkin, "setBlendMode", 792 | Q_ARG( int, 1 ) ); 793 | assert( im ); 794 | #endif 795 | } 796 | } 797 | } 798 | 799 | /** 800 | **/ 801 | void DzFbxImporter::fbxImport() 802 | { 803 | fbxPickAnimation(); 804 | 805 | m_root = new Node(); 806 | m_root->fbxNode = m_fbxScene->GetRootNode(); 807 | 808 | fbxImportGraph( m_root ); 809 | 810 | fbxImportSkinning(); 811 | 812 | fbxImportAnimation( m_root ); 813 | 814 | if ( m_includeAnimations ) 815 | { 816 | dzScene->setAnimRange( DzTimeRange( dzScene->getAnimRange().getStart(), m_dsEndTime ) ); 817 | dzScene->setPlayRange( DzTimeRange( dzScene->getAnimRange().getStart(), m_dsEndTime ) ); 818 | } 819 | 820 | QMap::iterator nodeFaceGroupIt; 821 | for ( nodeFaceGroupIt = m_nodeFaceGroupMap.begin(); nodeFaceGroupIt != m_nodeFaceGroupMap.end(); ++nodeFaceGroupIt ) 822 | { 823 | updateSelectionMap( nodeFaceGroupIt.key() ); 824 | } 825 | } 826 | 827 | /** 828 | **/ 829 | void DzFbxImporter::fbxCleanup() 830 | { 831 | if ( m_fbxManager ) 832 | { 833 | m_fbxManager->Destroy(); 834 | } 835 | 836 | m_fbxManager = NULL; 837 | } 838 | 839 | /** 840 | @param filename The full path of the file to import. 841 | @param impOptions The options to use while importing the file. 842 | 843 | @return DZ_NO_ERROR if the file was successfully imported. 844 | **/ 845 | DzError DzFbxImporter::read( const QString &filename, const DzFileIOSettings* impOptions ) 846 | { 847 | DzFileIOSettings options; 848 | const int isOK = getOptions( &options, impOptions, filename ); 849 | if ( !isOK ) 850 | { 851 | return DZ_USER_CANCELLED_OPERATION; 852 | } 853 | 854 | // Properties 855 | m_includeRotationLimits = options.getBoolValue( c_optIncRotationLimits, c_defaultIncludeRotationLimits ); 856 | m_includeAnimations = options.getBoolValue( c_optIncAnimations, c_defaultIncludeAnimations ); 857 | m_takeName = options.getStringValue( c_optTake, QString() ); 858 | 859 | // Geometry 860 | m_includePolygonSets = options.getBoolValue( c_optIncPolygonSets, c_defaultIncludePolygonSets ); 861 | m_includePolygonGroups = options.getBoolValue( c_optIncPolygonGroups, c_defaultIncludePolygonGroups ); 862 | 863 | // Custom Data 864 | m_studioNodeNamesLabels = options.getBoolValue( c_optStudioNodeNamesLabels, c_defaultStudioNodeNames ); 865 | m_studioNodePresentation = options.getBoolValue( c_optStudioPresentation, c_defaultStudioNodePresentation ); 866 | m_studioNodeSelectionMap = options.getBoolValue( c_optStudioNodeSelectionMap, c_defaultStudioNodeSelectionMap ); 867 | m_studioSceneIDs = options.getBoolValue( c_optStudioSceneIDs, c_defaultStudioSceneIDs ); 868 | 869 | #if DZ_SDK_4_12_OR_GREATER 870 | clearImportedNodes(); 871 | #endif 872 | 873 | m_folder = filename; 874 | m_folder.cdUp(); 875 | 876 | fbxRead( filename ); 877 | fbxImport(); 878 | fbxCleanup(); 879 | 880 | bool allTransparent = true; 881 | for ( int i = 0; i < m_dsMaterials.size() && allTransparent; i++ ) 882 | { 883 | if ( m_dsMaterials[i]->getBaseOpacity() > 0.1 ) 884 | { 885 | allTransparent = false; 886 | } 887 | } 888 | 889 | if ( allTransparent ) 890 | { 891 | for ( int i = 0; i < m_dsMaterials.size() && allTransparent; i++ ) 892 | { 893 | m_dsMaterials[i]->setBaseOpacity( 1 ); 894 | } 895 | } 896 | 897 | return DZ_NO_ERROR; 898 | } 899 | 900 | /** 901 | **/ 902 | QString DzFbxImporter::getFileVersion() const 903 | { 904 | QString sdkStr( "Unknown" ); 905 | const QString versionStr( "%1 (%2.%3.%4)%5" ); 906 | switch ( m_fbxFileMajor ) 907 | { 908 | case 7: 909 | switch( m_fbxFileMinor ) 910 | { 911 | case 7: 912 | sdkStr = "FBX 2019"; 913 | break; 914 | case 5: 915 | sdkStr = "FBX 2016/2017"; 916 | break; 917 | case 4: 918 | sdkStr = "FBX 2014/2015"; 919 | break; 920 | case 3: 921 | sdkStr = "FBX 2013"; 922 | break; 923 | case 2: 924 | sdkStr = "FBX 2012"; 925 | break; 926 | case 1: 927 | sdkStr = "FBX 2011"; 928 | break; 929 | default: 930 | break; 931 | } 932 | break; 933 | case 6: 934 | switch( m_fbxFileMinor ) 935 | { 936 | case 1: 937 | sdkStr = "FBX 2006/2009/2010"; 938 | break; 939 | default: 940 | break; 941 | } 942 | break; 943 | default: 944 | break; 945 | } 946 | 947 | return versionStr 948 | .arg( sdkStr ) 949 | .arg( m_fbxFileMajor ) 950 | .arg( m_fbxFileMinor ) 951 | .arg( m_fbxFileRevision ) 952 | .arg( getFileFormat() ); 953 | } 954 | 955 | /** 956 | **/ 957 | QString DzFbxImporter::getFileCreator() const 958 | { 959 | return QString( m_fbxFileCreator ); 960 | } 961 | 962 | /** 963 | **/ 964 | QString DzFbxImporter::getFileFormat() const 965 | { 966 | switch ( m_fbxFileBinary ) 967 | { 968 | default: 969 | case -1: 970 | return QString(); 971 | case 0: 972 | return " -- Ascii"; 973 | case 1: 974 | return " -- Binary"; 975 | } 976 | } 977 | 978 | /** 979 | **/ 980 | QString DzFbxImporter::getSceneAuthor() const 981 | { 982 | return QString( m_fbxSceneAuthor ); 983 | } 984 | 985 | /** 986 | **/ 987 | QString DzFbxImporter::getSceneTitle() const 988 | { 989 | return QString( m_fbxSceneTitle ); 990 | } 991 | 992 | /** 993 | **/ 994 | QString DzFbxImporter::getSceneSubject() const 995 | { 996 | return QString( m_fbxSceneSubject ); 997 | } 998 | 999 | /** 1000 | **/ 1001 | QString DzFbxImporter::getSceneKeywords() const 1002 | { 1003 | return QString( m_fbxSceneKeywords ); 1004 | } 1005 | 1006 | /** 1007 | **/ 1008 | QString DzFbxImporter::getSceneRevision() const 1009 | { 1010 | return QString( m_fbxSceneRevision ); 1011 | } 1012 | 1013 | /** 1014 | **/ 1015 | QString DzFbxImporter::getSceneComment() const 1016 | { 1017 | return QString( m_fbxSceneComment ); 1018 | } 1019 | 1020 | /** 1021 | **/ 1022 | QString DzFbxImporter::getOriginalAppVendor() const 1023 | { 1024 | return QString( m_fbxOrigAppVendor ); 1025 | } 1026 | 1027 | /** 1028 | **/ 1029 | QString DzFbxImporter::getOriginalAppName() const 1030 | { 1031 | return QString( m_fbxOrigAppName ); 1032 | } 1033 | 1034 | /** 1035 | **/ 1036 | QString DzFbxImporter::getOriginalAppVersion() const 1037 | { 1038 | return QString( m_fbxOrigAppVersion ); 1039 | } 1040 | 1041 | /** 1042 | **/ 1043 | QStringList DzFbxImporter::getAnimStackNames() const 1044 | { 1045 | return m_animStackNames; 1046 | } 1047 | 1048 | /** 1049 | **/ 1050 | void DzFbxImporter::setRotationLimits( bool enable ) 1051 | { 1052 | m_includeRotationLimits = enable; 1053 | } 1054 | 1055 | /** 1056 | **/ 1057 | void DzFbxImporter::setIncludeAnimations( bool enable ) 1058 | { 1059 | m_includeAnimations = enable; 1060 | } 1061 | 1062 | /** 1063 | **/ 1064 | void DzFbxImporter::setTakeName( const QString &name ) 1065 | { 1066 | m_takeName = name; 1067 | } 1068 | 1069 | /** 1070 | **/ 1071 | void DzFbxImporter::setIncludePolygonSets( bool enable ) 1072 | { 1073 | m_includePolygonSets = enable; 1074 | } 1075 | 1076 | /** 1077 | **/ 1078 | void DzFbxImporter::setIncludePolygonGroups( bool enable ) 1079 | { 1080 | m_includePolygonGroups = enable; 1081 | } 1082 | 1083 | /** 1084 | **/ 1085 | void DzFbxImporter::setStudioNodeNamesLabels( bool enable ) 1086 | { 1087 | m_studioNodeNamesLabels = enable; 1088 | } 1089 | 1090 | /** 1091 | **/ 1092 | void DzFbxImporter::setStudioNodePresentation( bool enable ) 1093 | { 1094 | m_studioNodePresentation = enable; 1095 | } 1096 | 1097 | /** 1098 | **/ 1099 | void DzFbxImporter::setStudioNodeSelectionMap( bool enable ) 1100 | { 1101 | m_studioNodeSelectionMap = enable; 1102 | } 1103 | 1104 | /** 1105 | **/ 1106 | void DzFbxImporter::setStudioSceneIDs( bool enable ) 1107 | { 1108 | m_studioSceneIDs = enable; 1109 | } 1110 | 1111 | /** 1112 | **/ 1113 | QStringList DzFbxImporter::getErrorList() const 1114 | { 1115 | return m_errorList; 1116 | } 1117 | 1118 | /** 1119 | **/ 1120 | void DzFbxImporter::replicateSkeleton( DzSkeleton* dsBaseSkeleton, const Skinning &skinning ) 1121 | { 1122 | Node* node = skinning.node; 1123 | DzSkeleton* dsSkeleton = qobject_cast( node->dsNode ); 1124 | if ( !dsSkeleton ) 1125 | { 1126 | return; 1127 | } 1128 | 1129 | const Node* baseNode = m_root->find( dsBaseSkeleton ); 1130 | 1131 | for ( int i = 0, n = baseNode->children.count(); i < n; i++ ) 1132 | { 1133 | const Node* baseChild = baseNode->children.at( i ); 1134 | const FbxNodeAttribute* fbxBaseNodeAttr = baseChild->fbxNode->GetNodeAttribute(); 1135 | if ( fbxBaseNodeAttr && fbxBaseNodeAttr->GetAttributeType() == FbxNodeAttribute::eMesh ) 1136 | { 1137 | continue; 1138 | } 1139 | 1140 | Node* child = new Node(); 1141 | child->setParent( node ); 1142 | child->fbxNode = baseChild->fbxNode; 1143 | child->dsParent = node->dsNode; 1144 | 1145 | fbxImportGraph( child ); 1146 | } 1147 | 1148 | dsSkeleton->setFollowTarget( dsBaseSkeleton ); 1149 | } 1150 | 1151 | static DzVec3 toVec3( FbxVector4 v ) 1152 | { 1153 | DzVec3 r; 1154 | r.m_x = v[0]; 1155 | r.m_y = v[1]; 1156 | r.m_z = v[2]; 1157 | r.m_w = v[3]; 1158 | return r; 1159 | } 1160 | 1161 | static FbxVector4 calcFbxRotationOffset( FbxNode* fbxNode ) 1162 | { 1163 | FbxVector4 offset( 0, 0, 0 ); 1164 | while ( fbxNode ) 1165 | { 1166 | bool applyOffset = true; 1167 | 1168 | if ( fbxNode->GetNodeAttribute() 1169 | && fbxNode->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eMesh ) 1170 | { 1171 | applyOffset = false; 1172 | } 1173 | 1174 | if ( applyOffset ) 1175 | { 1176 | offset += fbxNode->GetRotationOffset( FbxNode::eSourcePivot ); 1177 | } 1178 | 1179 | fbxNode = fbxNode->GetParent(); 1180 | } 1181 | offset[3] = 1; 1182 | return offset; 1183 | } 1184 | 1185 | static void setNodeOrientation( DzNode* dsNode, FbxNode* fbxNode ) 1186 | { 1187 | FbxVector4 fbxPre = fbxNode->GetPreRotation( FbxNode::eSourcePivot ); 1188 | const DzQuat rot( DzRotationOrder::XYZ, DzVec3( fbxPre[0], fbxPre[1], fbxPre[2] ) * DZ_FLT_DEG_TO_RAD ); 1189 | 1190 | dsNode->setOrientation( rot, true ); 1191 | } 1192 | 1193 | static void setNodeRotationOrder( DzNode* dsNode, FbxNode* fbxNode ) 1194 | { 1195 | DzRotationOrder dsRotationOrder( DzRotationOrder::XYZ ); 1196 | EFbxRotationOrder fbxRotationOrder( eEulerXYZ ); 1197 | 1198 | fbxNode->GetRotationOrder( FbxNode::eSourcePivot, fbxRotationOrder ); 1199 | switch ( fbxRotationOrder ) 1200 | { 1201 | case eEulerXYZ: 1202 | dsRotationOrder = DzRotationOrder::XYZ; 1203 | break; 1204 | case eEulerXZY: 1205 | dsRotationOrder = DzRotationOrder::XZY; 1206 | break; 1207 | case eEulerYXZ: 1208 | dsRotationOrder = DzRotationOrder::YXZ; 1209 | break; 1210 | case eEulerYZX: 1211 | dsRotationOrder = DzRotationOrder::YZX; 1212 | break; 1213 | case eEulerZXY: 1214 | dsRotationOrder = DzRotationOrder::ZXY; 1215 | break; 1216 | case eEulerZYX: 1217 | dsRotationOrder = DzRotationOrder::ZYX; 1218 | break; 1219 | default: 1220 | break; 1221 | } 1222 | 1223 | dsNode->setRotationOrder( dsRotationOrder ); 1224 | } 1225 | 1226 | static void setNodeRotation( DzNode* dsNode, FbxNode* fbxNode ) 1227 | { 1228 | const FbxDouble3 lclRotation = fbxNode->LclRotation.Get(); 1229 | 1230 | //dsNode->getXRotControl()->setDefaultValue( lclRotation[0] ); 1231 | //dsNode->getYRotControl()->setDefaultValue( lclRotation[1] ); 1232 | //dsNode->getZRotControl()->setDefaultValue( lclRotation[2] ); 1233 | dsNode->getXRotControl()->setValue( lclRotation[0] ); 1234 | dsNode->getYRotControl()->setValue( lclRotation[1] ); 1235 | dsNode->getZRotControl()->setValue( lclRotation[2] ); 1236 | } 1237 | 1238 | static void setNodeRotationLimits( DzNode* dsNode, FbxNode* fbxNode ) 1239 | { 1240 | const FbxLimits rotationLimits = fbxNode->GetRotationLimits(); 1241 | if ( !rotationLimits.GetActive() ) 1242 | { 1243 | return; 1244 | } 1245 | 1246 | const FbxDouble3 min = rotationLimits.GetMin(); 1247 | const FbxDouble3 max = rotationLimits.GetMax(); 1248 | 1249 | if ( rotationLimits.GetMaxXActive() 1250 | && rotationLimits.GetMinXActive() ) 1251 | { 1252 | dsNode->getXRotControl()->setIsClamped( true ); 1253 | dsNode->getXRotControl()->setMinMax( min[0], max[0] ); 1254 | } 1255 | 1256 | if ( rotationLimits.GetMaxYActive() 1257 | && rotationLimits.GetMinYActive() ) 1258 | { 1259 | dsNode->getYRotControl()->setIsClamped( true ); 1260 | dsNode->getYRotControl()->setMinMax( min[1], max[1] ); 1261 | } 1262 | 1263 | if ( rotationLimits.GetMaxZActive() 1264 | && rotationLimits.GetMinZActive() ) 1265 | { 1266 | dsNode->getZRotControl()->setIsClamped( true ); 1267 | dsNode->getZRotControl()->setMinMax( min[2], max[2] ); 1268 | } 1269 | } 1270 | 1271 | static void setNodeTranslation( DzNode* dsNode, FbxNode* fbxNode, DzVec3 translationOffset ) 1272 | { 1273 | const FbxDouble3 translation = fbxNode->LclTranslation.Get(); 1274 | 1275 | const float posX = translation[0] - translationOffset[0]; 1276 | const float posY = translation[1] - translationOffset[1]; 1277 | const float posZ = translation[2] - translationOffset[2]; 1278 | 1279 | //dsNode->getXPosControl()->setDefaultValue( posX ); 1280 | //dsNode->getYPosControl()->setDefaultValue( posY ); 1281 | //dsNode->getZPosControl()->setDefaultValue( posZ ); 1282 | dsNode->getXPosControl()->setValue( posX ); 1283 | dsNode->getYPosControl()->setValue( posY ); 1284 | dsNode->getZPosControl()->setValue( posZ ); 1285 | } 1286 | 1287 | static void setNodeInheritsScale( DzNode* dsNode, FbxNode* fbxNode ) 1288 | { 1289 | FbxTransform::EInheritType inheritType; 1290 | fbxNode->GetTransformationInheritType( inheritType ); 1291 | dsNode->setInheritScale( inheritType != FbxTransform::eInheritRrs ); 1292 | } 1293 | 1294 | static void setNodeScaling( DzNode* dsNode, FbxNode* fbxNode ) 1295 | { 1296 | const FbxDouble3 scaling = fbxNode->LclScaling.Get(); 1297 | 1298 | //dsNode->getXScaleControl()->setDefaultValue( scaling[0] ); 1299 | //dsNode->getYScaleControl()->setDefaultValue( scaling[1] ); 1300 | //dsNode->getZScaleControl()->setDefaultValue( scaling[2] ); 1301 | dsNode->getXScaleControl()->setValue( scaling[0] ); 1302 | dsNode->getYScaleControl()->setValue( scaling[1] ); 1303 | dsNode->getZScaleControl()->setValue( scaling[2] ); 1304 | } 1305 | 1306 | static void setNodeSceneID( DzNode* dsNode, FbxNode* fbxNode ) 1307 | { 1308 | QString dsSceneId; 1309 | 1310 | #if FBXSDK_VERSION_MAJOR >= 2016 1311 | const FbxProperty fbxSceneIdProperty = fbxNode->FindProperty( "StudioSceneID" ); 1312 | if ( fbxSceneIdProperty.IsValid() ) 1313 | { 1314 | dsSceneId = QString( fbxSceneIdProperty.Get() ); 1315 | } 1316 | #endif 1317 | 1318 | if ( dsSceneId.isEmpty() ) 1319 | { 1320 | return; 1321 | } 1322 | 1323 | const DzUri nodeUri( dsSceneId ); 1324 | if ( nodeUri.getFilePath().isEmpty() ) 1325 | { 1326 | return; 1327 | } 1328 | 1329 | dsNode->modifyAsset( nodeUri ); //cause assetUri to be set 1330 | dsNode->modifyAsset(); //cause assetUri to become the source and mark as modified 1331 | } 1332 | 1333 | static void setNodePresentation( DzNode* dsNode, FbxNode* fbxNode ) 1334 | { 1335 | QString presentationType; 1336 | QString autoFitBase; 1337 | QString preferredBase; 1338 | 1339 | #if FBXSDK_VERSION_MAJOR >= 2016 1340 | const FbxProperty fbxPresentationTypeProperty = fbxNode->FindProperty( "StudioPresentationType" ); 1341 | if ( fbxPresentationTypeProperty.IsValid() ) 1342 | { 1343 | presentationType = QString( fbxPresentationTypeProperty.Get() ); 1344 | } 1345 | 1346 | const FbxProperty fbxPresentationAutoFitBaseProperty = fbxNode->FindProperty( "StudioPresentationAutoFitBase" ); 1347 | if ( fbxPresentationAutoFitBaseProperty.IsValid() ) 1348 | { 1349 | autoFitBase = QString( fbxPresentationAutoFitBaseProperty.Get() ); 1350 | } 1351 | 1352 | const FbxProperty fbxPresentationPreferredBaseProperty = fbxNode->FindProperty( "StudioPresentationPreferredBase" ); 1353 | if ( fbxPresentationPreferredBaseProperty.IsValid() ) 1354 | { 1355 | preferredBase = QString( fbxPresentationPreferredBaseProperty.Get() ); 1356 | } 1357 | #endif 1358 | 1359 | if ( presentationType.isEmpty() 1360 | && autoFitBase.isEmpty() 1361 | && preferredBase.isEmpty() ) 1362 | { 1363 | return; 1364 | } 1365 | 1366 | DzPresentation* presentation = dsNode->getPresentation(); 1367 | if ( !presentation ) 1368 | { 1369 | presentation = new DzPresentation(); 1370 | dsNode->setPresentation( presentation ); 1371 | } 1372 | 1373 | if ( !presentationType.isEmpty() ) 1374 | { 1375 | presentation->setType( presentationType ); 1376 | } 1377 | 1378 | if ( !autoFitBase.isEmpty() ) 1379 | { 1380 | #if DZ_SDK_4_12_OR_GREATER 1381 | presentation->setAutoFitBase( autoFitBase ); 1382 | #else 1383 | // DzPresentation::setAutoFitBase() is not in the 4.5 SDK, so we attempt 1384 | // to use the meta-object to access/set the DzPresentation::autoFitBase 1385 | // property - since 4.5.2.13. 1386 | 1387 | presentation->setProperty( "autoFitBase", autoFitBase ); 1388 | #endif //DZ_SDK_4_12_OR_GREATER 1389 | } 1390 | 1391 | if ( !preferredBase.isEmpty() ) 1392 | { 1393 | #if DZ_SDK_4_12_OR_GREATER 1394 | presentation->setPreferredBase( preferredBase ); 1395 | #else 1396 | // DzPresentation::setPreferredBase() is not in the 4.5 SDK, so we attempt 1397 | // to use the meta-object to access/set the DzPresentation::preferredBase 1398 | // property - since 4.5.2.13. 1399 | 1400 | presentation->setProperty( "preferredBase", preferredBase ); 1401 | #endif //DZ_SDK_4_12_OR_GREATER 1402 | } 1403 | } 1404 | 1405 | static bool isFuzzyClose( double a, double b, double c ) 1406 | { 1407 | if ( qAbs( a - b ) > 0.0000000001f 1408 | || qAbs( a - c ) > 0.0000000001f ) 1409 | { 1410 | return false; 1411 | } 1412 | 1413 | return true; 1414 | } 1415 | 1416 | /** 1417 | **/ 1418 | void DzFbxImporter::fbxPreImportAnimationStack() 1419 | { 1420 | for ( int i = 0, n = m_fbxScene->GetSrcObjectCount(); i < n; i++ ) 1421 | { 1422 | const FbxAnimStack* animStack = m_fbxScene->GetSrcObject( i ); 1423 | 1424 | const QString stackName( animStack->GetName() ); 1425 | 1426 | const int numLayers = animStack->GetMemberCount(); 1427 | if ( numLayers == 0 ) 1428 | { 1429 | m_errorList << "Animation: \"" % stackName % "\" has no layers."; 1430 | } 1431 | else if ( numLayers > 1 ) 1432 | { 1433 | m_errorList << "Animation: \"" % stackName % "\" has multiple layers."; 1434 | } 1435 | 1436 | m_animStackNames.push_back( stackName ); 1437 | } 1438 | } 1439 | 1440 | /** 1441 | **/ 1442 | void DzFbxImporter::fbxPreImportGraph( FbxNode* fbxNode ) 1443 | { 1444 | const QString nodeName( fbxNode->GetName() ); 1445 | 1446 | if ( !m_suppressRigErrors ) 1447 | { 1448 | // pre (Joint Orient)/post (Rotate Axis) rotation must match 1449 | if ( fbxNode->GetPreRotation( FbxNode::eSourcePivot ) != fbxNode->GetPostRotation( FbxNode::eSourcePivot ) ) 1450 | { 1451 | m_errorList << "Rigging: Pre/Post rotation mismatch: " % nodeName; 1452 | } 1453 | 1454 | // scale must be uniform 1455 | FbxDouble3 fbxScaling = fbxNode->LclScaling.Get(); 1456 | if ( !isFuzzyClose( fbxScaling[0], fbxScaling[1], fbxScaling[2] ) ) 1457 | { 1458 | m_errorList << "Rigging: Non-uniform scale: " % nodeName; 1459 | } 1460 | 1461 | // mesh 1462 | if ( const FbxMesh* fbxMesh = fbxNode->GetMesh() ) 1463 | { 1464 | // we are only concerned with skinning at the moment 1465 | const int numSkins = fbxMesh->GetDeformerCount( FbxDeformer::eSkin ); 1466 | for ( int i = 0; i < numSkins; i++ ) 1467 | { 1468 | // skinning weights must be linked to a bone 1469 | 1470 | FbxSkin* fbxSkin = FbxCast( fbxMesh->GetDeformer( i ) ); 1471 | for ( int j = 0, m = fbxSkin->GetClusterCount(); j < m; j++ ) 1472 | { 1473 | FbxNode* fbxClusterNode = fbxSkin->GetCluster( j )->GetLink(); 1474 | if ( fbxClusterNode && fbxClusterNode->GetSkeleton() ) 1475 | { 1476 | continue; 1477 | } 1478 | 1479 | m_errorList << "Rigging: Cluster linked to non-bone: " % QString( fbxClusterNode->GetName() ); 1480 | } 1481 | } 1482 | } 1483 | 1484 | // "bone chains" 1485 | if ( const FbxSkeleton* fbxSkeleton = fbxNode->GetSkeleton() ) 1486 | { 1487 | // a "bone chain" must ultimately start with a "root"; if the 'current' 1488 | // skeleton node is not the root, it should have a parent that is 1489 | 1490 | const char* skelTypes[] = { "Root", "Limb", "Limb Node", "Effector" }; 1491 | 1492 | FbxSkeleton::EType skelType = fbxSkeleton->GetSkeletonType(); 1493 | switch ( skelType ) 1494 | { 1495 | default: 1496 | case FbxSkeleton::eRoot: 1497 | break; 1498 | case FbxSkeleton::eLimb: 1499 | case FbxSkeleton::eLimbNode: 1500 | case FbxSkeleton::eEffector: 1501 | { 1502 | FbxNode* fbxParentNode = fbxNode->GetParent(); 1503 | if ( !fbxParentNode 1504 | || !fbxParentNode->GetSkeleton() ) 1505 | { 1506 | m_errorList << "Rigging: Bone chain type incorrect - " % QString( skelTypes[skelType] ) % ": " % nodeName; 1507 | } 1508 | } 1509 | break; 1510 | } 1511 | } 1512 | } 1513 | 1514 | for ( int i = 0, n = fbxNode->GetChildCount(); i < n; i++ ) 1515 | { 1516 | fbxPreImportGraph( fbxNode->GetChild( i ) ); 1517 | } 1518 | } 1519 | 1520 | /** 1521 | **/ 1522 | void DzFbxImporter::fbxPreImport() 1523 | { 1524 | fbxPreImportAnimationStack(); 1525 | 1526 | FbxNode* fbxRootNode = m_fbxScene->GetRootNode(); 1527 | for ( int i = 0, n = fbxRootNode->GetChildCount(); i < n; i++ ) 1528 | { 1529 | fbxPreImportGraph( fbxRootNode->GetChild( i ) ); 1530 | } 1531 | } 1532 | 1533 | /** 1534 | **/ 1535 | void DzFbxImporter::fbxImportGraph( Node* node ) 1536 | { 1537 | if ( node == m_root ) 1538 | { 1539 | for ( int i = 0; i < node->fbxNode->GetChildCount(); i++ ) 1540 | { 1541 | Node* child = new Node(); 1542 | child->setParent( node ); 1543 | child->fbxNode = node->fbxNode->GetChild( i ); 1544 | } 1545 | 1546 | for ( int i = 0; i < node->children.count(); i++ ) 1547 | { 1548 | fbxImportGraph( node->children[i] ); 1549 | } 1550 | 1551 | return; 1552 | } 1553 | 1554 | DzNode* dsMeshNode = NULL; 1555 | 1556 | const FbxNull* fbxNull = node->fbxNode->GetNull(); 1557 | if ( fbxNull || !node->fbxNode->GetNodeAttribute() ) 1558 | { 1559 | node->dsNode = new DzNode(); 1560 | } 1561 | else 1562 | { 1563 | switch ( node->fbxNode->GetNodeAttribute()->GetAttributeType() ) 1564 | { 1565 | case FbxNodeAttribute::eMarker: 1566 | break; 1567 | case FbxNodeAttribute::eSkeleton: 1568 | { 1569 | const FbxSkeleton* fbxSkeleton = node->fbxNode->GetSkeleton(); 1570 | switch ( fbxSkeleton->GetSkeletonType() ) 1571 | { 1572 | case FbxSkeleton::eRoot: 1573 | node->dsNode = createFigure(); 1574 | break; 1575 | case FbxSkeleton::eLimb: //intentional fall-through 1576 | case FbxSkeleton::eLimbNode: 1577 | { 1578 | node->dsNode = new DzBone(); 1579 | node->dsNode->setInheritScale( true ); 1580 | 1581 | #if FBXSDK_VERSION_MAJOR >= 2016 1582 | FbxProperty fbxPropertyFaceGroup; 1583 | if ( m_studioNodeSelectionMap ) 1584 | { 1585 | fbxPropertyFaceGroup = node->fbxNode->FindProperty( "StudioNodeFaceGroup" ); 1586 | } 1587 | 1588 | if ( fbxPropertyFaceGroup.IsValid() ) 1589 | { 1590 | const QString selectionSetName( fbxPropertyFaceGroup.Get() ); 1591 | m_nodeFaceGroupMap.insert( node, selectionSetName ); 1592 | } 1593 | #endif 1594 | } 1595 | break; 1596 | case FbxSkeleton::eEffector: 1597 | break; 1598 | } 1599 | } 1600 | break; 1601 | case FbxNodeAttribute::eMesh: 1602 | { 1603 | const QString fbxNodeName( node->fbxNode->GetName() ); 1604 | if ( node->dsParent && 1605 | !node->dsParent->getObject() && 1606 | ( node->dsParent->getName() + ".Shape" == fbxNodeName || 1607 | node->dsParent->getName() + "_Shape" == fbxNodeName ) ) 1608 | { 1609 | dsMeshNode = node->dsParent; 1610 | } 1611 | else 1612 | { 1613 | const FbxMesh* fbxMesh = node->fbxNode->GetMesh(); 1614 | if ( fbxMesh->GetDeformerCount( FbxDeformer::eSkin ) > 0 ) 1615 | { 1616 | node->dsNode = createFigure(); 1617 | node->collapseTranslation = true; 1618 | } 1619 | else 1620 | { 1621 | node->dsNode = new DzNode(); 1622 | } 1623 | 1624 | dsMeshNode = node->dsNode; 1625 | } 1626 | 1627 | fbxImportMesh( node, node->fbxNode, dsMeshNode ); 1628 | } 1629 | break; 1630 | case FbxNodeAttribute::eNurbs: 1631 | break; 1632 | case FbxNodeAttribute::ePatch: 1633 | break; 1634 | case FbxNodeAttribute::eCamera: 1635 | break; 1636 | case FbxNodeAttribute::eLight: 1637 | break; 1638 | case FbxNodeAttribute::eLODGroup: 1639 | break; 1640 | default: 1641 | FbxNodeAttribute::EType type = node->fbxNode->GetNodeAttribute()->GetAttributeType(); 1642 | break; 1643 | } 1644 | } 1645 | 1646 | if ( node->dsNode ) 1647 | { 1648 | m_nodeMap[node->fbxNode] = node->dsNode; 1649 | 1650 | QString nodeName( node->fbxNode->GetName() ); 1651 | #if FBXSDK_VERSION_MAJOR >= 2016 1652 | FbxProperty fbxPropertyNodeName; 1653 | if ( m_studioNodeNamesLabels ) 1654 | { 1655 | fbxPropertyNodeName = node->fbxNode->FindProperty( "StudioNodeName" ); 1656 | } 1657 | 1658 | if ( fbxPropertyNodeName.IsValid() ) 1659 | { 1660 | nodeName = fbxPropertyNodeName.Get(); 1661 | } 1662 | #endif 1663 | node->dsNode->setName( nodeName ); 1664 | 1665 | if ( node->dsParent ) 1666 | { 1667 | node->dsParent->addNodeChild( node->dsNode ); 1668 | } 1669 | 1670 | #if FBXSDK_VERSION_MAJOR >= 2016 1671 | FbxProperty fbxPropertyNodeLabel; 1672 | if ( m_studioNodeNamesLabels ) 1673 | { 1674 | fbxPropertyNodeLabel = node->fbxNode->FindProperty( "StudioNodeLabel" ); 1675 | } 1676 | 1677 | if ( fbxPropertyNodeLabel.IsValid() ) 1678 | { 1679 | const QString nodeLabel( fbxPropertyNodeLabel.Get()); 1680 | node->dsNode->setLabel( dzScene->getUniqueTopLevelLabel( nodeLabel ) ); 1681 | } 1682 | #endif 1683 | 1684 | if ( m_studioNodePresentation ) 1685 | { 1686 | setNodePresentation( node->dsNode, node->fbxNode ); 1687 | } 1688 | 1689 | setNodeInheritsScale( node->dsNode, node->fbxNode ); 1690 | 1691 | const FbxVector4 rotationOffset = calcFbxRotationOffset( node->fbxNode ); 1692 | node->dsNode->setOrigin( toVec3( rotationOffset ), true ); 1693 | setNodeOrientation( node->dsNode, node->fbxNode ); 1694 | setNodeRotationOrder( node->dsNode, node->fbxNode ); 1695 | 1696 | if ( rotationOffset.SquareLength() == 0.0 ) 1697 | { 1698 | bool found = false; 1699 | FbxMatrix fbxMatrix; 1700 | 1701 | for ( int i = 0; i < m_fbxScene->GetPoseCount(); i++ ) 1702 | { 1703 | const FbxPose* pose = m_fbxScene->GetPose( i ); 1704 | if ( pose->IsBindPose() ) 1705 | { 1706 | for ( int j = 0; j < pose->GetCount(); j++ ) 1707 | { 1708 | if ( pose->GetNode( j ) == node->fbxNode ) 1709 | { 1710 | found = true; 1711 | fbxMatrix = pose->GetMatrix( j ); 1712 | } 1713 | } 1714 | } 1715 | } 1716 | 1717 | if ( !found ) 1718 | { 1719 | fbxMatrix = node->fbxNode->EvaluateGlobalTransform(); 1720 | } 1721 | 1722 | node->bindTranslation[0] = fbxMatrix[3][0]; 1723 | node->bindTranslation[1] = fbxMatrix[3][1]; 1724 | node->bindTranslation[2] = fbxMatrix[3][2]; 1725 | if ( !node->collapseTranslation ) 1726 | { 1727 | node->dsNode->setOrigin( node->bindTranslation, true ); 1728 | } 1729 | } 1730 | 1731 | if ( node->collapseTranslation && dsMeshNode ) 1732 | { 1733 | DzFacetMesh* dsFacetMesh = qobject_cast( dsMeshNode->getObject()->getCurrentShape()->getGeometry() ); 1734 | if ( dsFacetMesh ) 1735 | { 1736 | DzPnt3* vertices = dsFacetMesh->getVerticesPtr(); 1737 | for ( int i = 0; i < dsFacetMesh->getNumVertices(); i++ ) 1738 | { 1739 | vertices[i][0] += node->bindTranslation[0]; 1740 | vertices[i][1] += node->bindTranslation[1]; 1741 | vertices[i][2] += node->bindTranslation[2]; 1742 | } 1743 | } 1744 | } 1745 | 1746 | dzScene->addNode( node->dsNode ); 1747 | 1748 | #if DZ_SDK_4_12_OR_GREATER 1749 | addImportedNode( node->dsNode ); 1750 | #endif 1751 | 1752 | for ( int i = 0; i < node->fbxNode->GetChildCount(); i++ ) 1753 | { 1754 | Node* child = new Node(); 1755 | child->setParent( node ); 1756 | child->dsParent = node->dsNode; 1757 | child->fbxNode = node->fbxNode->GetChild( i ); 1758 | } 1759 | 1760 | for ( int i = 0; i < node->children.count(); i++ ) 1761 | { 1762 | fbxImportGraph( node->children[i] ); 1763 | } 1764 | 1765 | DzVec3 endPoint = node->dsNode->getOrigin(); 1766 | if ( node->dsNode->getNumNodeChildren() ) 1767 | { 1768 | endPoint = node->dsNode->getNodeChild( 0 )->getOrigin( true ); 1769 | for ( int i = 1; i < node->dsNode->getNumNodeChildren(); i++ ) 1770 | { 1771 | endPoint += node->dsNode->getNodeChild( i )->getOrigin( true ); 1772 | } 1773 | endPoint.m_x /= node->dsNode->getNumNodeChildren(); 1774 | endPoint.m_y /= node->dsNode->getNumNodeChildren(); 1775 | endPoint.m_z /= node->dsNode->getNumNodeChildren(); 1776 | node->dsNode->setEndPoint( endPoint, true ); 1777 | } 1778 | else 1779 | { 1780 | DzVec3 toCenter = endPoint; 1781 | if ( node->dsNode->getNodeParent() ) 1782 | { 1783 | toCenter -= node->dsNode->getNodeParent()->getOrigin(); 1784 | toCenter = ( node->dsNode->getNodeParent()->getOrientation().inverse() * node->dsNode->getOrientation() ).multVec( toCenter ); 1785 | if ( toCenter.length() > 1 ) 1786 | { 1787 | toCenter /= 2.0; 1788 | } 1789 | } 1790 | node->dsNode->setEndPoint( endPoint + toCenter, true ); 1791 | } 1792 | 1793 | // setup a decent guess so IK will work 1794 | if ( qobject_cast( node->dsNode ) && 1795 | qobject_cast( node->dsParent ) && 1796 | node->dsNode->getNumNodeChildren() != 0 ) 1797 | { 1798 | node->dsNode->getXPosControl()->setHidden( true ); 1799 | node->dsNode->getYPosControl()->setHidden( true ); 1800 | node->dsNode->getZPosControl()->setHidden( true ); 1801 | } 1802 | 1803 | if ( m_includeRotationLimits ) 1804 | { 1805 | setNodeRotationLimits( node->dsNode, node->fbxNode ); 1806 | } 1807 | 1808 | if ( m_studioSceneIDs ) 1809 | { 1810 | setNodeSceneID( node->dsNode, node->fbxNode ); 1811 | } 1812 | } 1813 | } 1814 | 1815 | /** 1816 | **/ 1817 | void DzFbxImporter::fbxImportAnimation( Node* node ) 1818 | { 1819 | if ( node->dsNode ) 1820 | { 1821 | if ( !node->collapseTranslation ) 1822 | { 1823 | DzVec3 translationOffset = node->bindTranslation; 1824 | if ( node->parent ) 1825 | { 1826 | translationOffset -= node->parent->bindTranslation; 1827 | } 1828 | 1829 | setNodeTranslation( node->dsNode, node->fbxNode, translationOffset ); 1830 | setNodeRotation( node->dsNode, node->fbxNode ); 1831 | 1832 | setNodeScaling( node->dsNode, node->fbxNode ); 1833 | } 1834 | 1835 | if ( m_fbxAnimLayer && !node->collapseTranslation ) 1836 | { 1837 | applyFbxCurve( node->fbxNode->LclTranslation.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X ), node->dsNode->getXPosControl() ); 1838 | applyFbxCurve( node->fbxNode->LclTranslation.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y ), node->dsNode->getYPosControl() ); 1839 | applyFbxCurve( node->fbxNode->LclTranslation.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z ), node->dsNode->getZPosControl() ); 1840 | 1841 | applyFbxCurve( node->fbxNode->LclRotation.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X ), node->dsNode->getXRotControl() ); 1842 | applyFbxCurve( node->fbxNode->LclRotation.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y ), node->dsNode->getYRotControl() ); 1843 | applyFbxCurve( node->fbxNode->LclRotation.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z ), node->dsNode->getZRotControl() ); 1844 | 1845 | applyFbxCurve( node->fbxNode->LclScaling.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X ), node->dsNode->getXScaleControl() ); 1846 | applyFbxCurve( node->fbxNode->LclScaling.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y ), node->dsNode->getYScaleControl() ); 1847 | applyFbxCurve( node->fbxNode->LclScaling.GetCurve( m_fbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z ), node->dsNode->getZScaleControl() ); 1848 | } 1849 | 1850 | 1851 | #if FBXSDK_VERSION_MAJOR >= 2016 1852 | for ( FbxProperty fbxProperty = node->fbxNode->GetFirstProperty(); fbxProperty.IsValid(); fbxProperty = node->fbxNode->GetNextProperty( fbxProperty ) ) 1853 | { 1854 | if ( !fbxProperty.GetFlag( FbxPropertyFlags::eUserDefined ) ) 1855 | { 1856 | continue; 1857 | } 1858 | 1859 | if ( node->dsNode->findDataItem( DATA_FBX_USER_PROPERTIES ) == NULL ) 1860 | { 1861 | node->dsNode->addDataItem( new DzSimpleElementData( DATA_FBX_USER_PROPERTIES, true ) ); 1862 | } 1863 | 1864 | const QString key( fbxProperty.GetName() ); 1865 | DzSimpleElementData* userPropertyData = qobject_cast( node->dsNode->findDataItem( DATA_FBX_USER_PROPERTIES ) ); 1866 | DzSettings* userSettings = userPropertyData->getSettings(); 1867 | 1868 | FbxDataType fbxPropertyData = fbxProperty.GetPropertyDataType(); 1869 | switch ( fbxPropertyData.GetType() ) 1870 | { 1871 | case eFbxInt: 1872 | userSettings->setIntValue( key, fbxProperty.Get() ); 1873 | break; 1874 | case eFbxBool: 1875 | userSettings->setBoolValue( key, fbxProperty.Get() ); 1876 | break; 1877 | case eFbxFloat: 1878 | userSettings->setFloatValue( key, fbxProperty.Get() ); 1879 | break; 1880 | case eFbxDouble: 1881 | userSettings->setFloatValue( key, fbxProperty.Get() ); 1882 | break; 1883 | case eFbxString: 1884 | userSettings->setStringValue( key, QString( fbxProperty.Get() ) ); 1885 | break; 1886 | default: 1887 | break; 1888 | } 1889 | } 1890 | #endif 1891 | } 1892 | 1893 | for ( int i = 0; i < node->children.count(); i++ ) 1894 | { 1895 | fbxImportAnimation( node->children[i] ); 1896 | } 1897 | } 1898 | 1899 | 1900 | static QColor toQColor( FbxPropertyT fbxValue ) 1901 | { 1902 | QColor clr; 1903 | 1904 | clr.setRedF( fbxValue.Get()[0] ); 1905 | clr.setGreenF( fbxValue.Get()[1] ); 1906 | clr.setBlueF( fbxValue.Get()[2] ); 1907 | 1908 | return clr; 1909 | } 1910 | 1911 | /** 1912 | **/ 1913 | DzTexture* DzFbxImporter::toTexture( FbxProperty fbxProperty ) 1914 | { 1915 | for ( int i = 0; i < fbxProperty.GetSrcObjectCount(); ++i ) 1916 | { 1917 | const FbxFileTexture* fbxFileTexture = fbxProperty.GetSrcObject( i ); 1918 | const DzImageMgr* imgMgr = dzApp->getImageMgr(); 1919 | DzTexture* dsTexture = imgMgr->getImage( fbxFileTexture->GetFileName() ); 1920 | if ( !dsTexture ) 1921 | { 1922 | dsTexture = imgMgr->getImage( m_folder.filePath( fbxFileTexture->GetFileName() ) ); 1923 | } 1924 | 1925 | return dsTexture; 1926 | } 1927 | 1928 | return 0; 1929 | } 1930 | 1931 | /** 1932 | **/ 1933 | void DzFbxImporter::fbxImportVertices( int numVertices, FbxVector4* fbxVertices, DzFacetMesh* dsMesh, DzVec3 offset ) 1934 | { 1935 | DzPnt3* dsVertices = dsMesh->setVertexArray( numVertices ); 1936 | for ( int i = 0; i < numVertices; i++ ) 1937 | { 1938 | dsVertices[i][0] = fbxVertices[i][0] + offset[0]; 1939 | dsVertices[i][1] = fbxVertices[i][1] + offset[1]; 1940 | dsVertices[i][2] = fbxVertices[i][2] + offset[2]; 1941 | } 1942 | } 1943 | 1944 | /** 1945 | **/ 1946 | void DzFbxImporter::fbxImportUVs( FbxMesh* fbxMesh, DzFacetMesh* dsMesh ) 1947 | { 1948 | for ( int i = 0, n = fbxMesh->GetElementUVCount(); i < n; i++ ) 1949 | { 1950 | const FbxGeometryElementUV* fbxGeomUv = fbxMesh->GetElementUV( i ); 1951 | const int numUvs = fbxGeomUv->GetDirectArray().GetCount(); 1952 | 1953 | DzMap* dsUvMap = dsMesh->getUVs(); 1954 | dsUvMap->setNumValues( numUvs ); 1955 | DzPnt2* dsUVs = dsUvMap->getPnt2ArrayPtr(); 1956 | 1957 | for ( int j = 0; j < numUvs; j++ ) 1958 | { 1959 | const FbxVector2 fbxUv = fbxGeomUv->GetDirectArray().GetAt( j ); 1960 | dsUVs[j][0] = fbxUv[0]; 1961 | dsUVs[j][1] = fbxUv[1]; 1962 | } 1963 | 1964 | // only do the first 1965 | break; 1966 | } 1967 | } 1968 | 1969 | /** 1970 | **/ 1971 | void DzFbxImporter::fbxImportSubdVertexWeights( FbxMesh* fbxMesh, DzFacetMesh* dsMesh, bool &enableSubd ) 1972 | { 1973 | for ( int i = 0, n = fbxMesh->GetElementVertexCreaseCount(); i < n; i++ ) 1974 | { 1975 | const FbxGeometryElementCrease* fbxSubdVertexCrease = fbxMesh->GetElementVertexCrease( i ); 1976 | for ( int j = 0, m = fbxSubdVertexCrease->GetDirectArray().GetCount(); j < m; j++ ) 1977 | { 1978 | const double weight = fbxSubdVertexCrease->GetDirectArray().GetAt( j ); 1979 | if ( weight > 0 ) 1980 | { 1981 | enableSubd = true; 1982 | 1983 | #if DZ_SDK_4_12_OR_GREATER 1984 | dsMesh->setVertexWeight( j, weight ); 1985 | #else 1986 | // DzFacetMesh::setVertexWeight() is not in the 4.5 SDK, so we 1987 | // attempt to use the meta-object to call the method. 1988 | 1989 | bool im = QMetaObject::invokeMethod( dsMesh, "setVertexWeight", 1990 | Q_ARG( int, j ), Q_ARG( int, weight ) ); 1991 | assert( im ); 1992 | #endif 1993 | } 1994 | } 1995 | 1996 | // only do the first 1997 | break; 1998 | } 1999 | } 2000 | 2001 | /** 2002 | **/ 2003 | void DzFbxImporter::fbxImportMaterials( FbxNode* fbxNode, FbxMesh* fbxMesh, DzFacetMesh* dsMesh, DzFacetShape* dsShape, bool &matsAllSame ) 2004 | { 2005 | for ( int i = 0, n = fbxNode->GetMaterialCount(); i < n; i++ ) 2006 | { 2007 | QColor diffuseColor = Qt::white; 2008 | DzTexturePtr diffuseMap = NULL; 2009 | 2010 | float diffuseFactor = 1.0f; 2011 | 2012 | float opacityBase = 1.0f; 2013 | DzTexturePtr opacityMap = NULL; 2014 | 2015 | QColor ambientColor = Qt::black; 2016 | DzTexturePtr ambientMap = NULL; 2017 | 2018 | float ambientFactor = 1.0f; 2019 | 2020 | QColor specularColor = Qt::white; 2021 | DzTexturePtr specularMap = NULL; 2022 | 2023 | float specularFactor = 1.0f; 2024 | 2025 | float shininess = 1.0f; 2026 | DzTexturePtr shininessMap = NULL; 2027 | 2028 | float reflectionFactor = 1.0f; 2029 | DzTexturePtr reflectionMap = NULL; 2030 | 2031 | float roughness = 0.1f; 2032 | float metallicity = 1.0f; 2033 | 2034 | FbxSurfaceMaterial* fbxMaterial = fbxNode->GetMaterial( i ); 2035 | DzMaterialPtr dsMaterial = NULL; 2036 | 2037 | const DzClassFactory* pbrMatFactory = dzApp->findClassFactory( "DzPbrMaterial" ); //or "DzUberIrayMaterial" 2038 | if ( QObject* pbrMatInstance = pbrMatFactory ? pbrMatFactory->createInstance() : NULL ) 2039 | { 2040 | dsMaterial = qobject_cast( pbrMatInstance ); 2041 | } 2042 | else 2043 | { 2044 | dsMaterial = new DzDefaultMaterial(); 2045 | } 2046 | 2047 | DzDefaultMaterial* dsDefMaterial = qobject_cast( dsMaterial ); 2048 | 2049 | FbxSurfacePhong* fbxPhong = FbxCast( fbxMaterial ); 2050 | if ( fbxPhong ) 2051 | { 2052 | diffuseColor = toQColor( fbxPhong->Diffuse ); 2053 | diffuseMap = toTexture( fbxPhong->Diffuse ); 2054 | 2055 | // Maya and Max want transparency in the color 2056 | opacityBase = 1 - (fbxPhong->TransparentColor.Get()[0] + fbxPhong->TransparentColor.Get()[1] + fbxPhong->TransparentColor.Get()[2]) / 3; 2057 | opacityMap = toTexture( fbxPhong->TransparentColor ); 2058 | 2059 | if ( dsDefMaterial ) 2060 | { 2061 | diffuseFactor = fbxPhong->DiffuseFactor.Get(); 2062 | 2063 | ambientColor = toQColor( fbxPhong->Ambient ); 2064 | ambientMap = toTexture( fbxPhong->Ambient ); 2065 | 2066 | ambientFactor = fbxPhong->AmbientFactor.Get(); 2067 | 2068 | specularColor = toQColor( fbxPhong->Specular ); 2069 | specularMap = toTexture( fbxPhong->Specular ); 2070 | 2071 | specularFactor = fbxPhong->SpecularFactor.Get(); 2072 | 2073 | shininess = fbxPhong->Shininess.Get(); 2074 | shininessMap = toTexture( fbxPhong->Shininess ); 2075 | 2076 | reflectionFactor = fbxPhong->ReflectionFactor.Get(); 2077 | reflectionMap = toTexture( fbxPhong->ReflectionFactor ); 2078 | } 2079 | else //DzPbrMaterial or DzUberIrayMaterial 2080 | { 2081 | roughness = 1.0 - ((log( fbxPhong->Shininess.Get() ) / log( 2.0 )) - 2) / 10; 2082 | 2083 | FbxDouble3 spec = fbxPhong->Specular.Get(); 2084 | float innerDistance = qAbs( spec[1] - spec[0] ) + qAbs( spec[2] - spec[0] ) + qAbs( spec[2] - spec[1] ); 2085 | metallicity = qMin( 1.0f, innerDistance ); 2086 | } 2087 | } 2088 | else if ( FbxSurfaceLambert* fbxLambert = FbxCast( fbxMaterial ) ) 2089 | { 2090 | diffuseColor = toQColor( fbxLambert->Diffuse ); 2091 | diffuseMap = toTexture( fbxLambert->Diffuse ); 2092 | 2093 | // Maya and Max want transparency in the color 2094 | opacityBase = 1 - (fbxLambert->TransparentColor.Get()[0] + fbxLambert->TransparentColor.Get()[1] + fbxLambert->TransparentColor.Get()[2]) / 3; 2095 | opacityMap = toTexture( fbxLambert->TransparentColor ); 2096 | 2097 | if ( dsDefMaterial ) 2098 | { 2099 | ambientColor = toQColor( fbxLambert->Ambient ); 2100 | ambientMap = toTexture( fbxLambert->Ambient ); 2101 | 2102 | ambientFactor = fbxLambert->AmbientFactor.Get(); 2103 | } 2104 | } 2105 | 2106 | dsMaterial->setName( fbxMaterial->GetName() ); 2107 | 2108 | dsMaterial->setDiffuseColor( diffuseColor ); 2109 | dsMaterial->setColorMap( diffuseMap ); 2110 | 2111 | dsMaterial->setBaseOpacity( opacityBase ); 2112 | dsMaterial->setOpacityMap( opacityMap ); 2113 | 2114 | if ( dsDefMaterial ) 2115 | { 2116 | dsDefMaterial->setAmbientColor( ambientColor ); 2117 | dsDefMaterial->setAmbientColorMap( ambientMap ); 2118 | 2119 | dsDefMaterial->setAmbientStrength( ambientFactor ); 2120 | 2121 | if ( fbxPhong ) 2122 | { 2123 | dsDefMaterial->setDiffuseStrength( diffuseFactor ); 2124 | 2125 | dsDefMaterial->setSpecularColor( specularColor ); 2126 | dsDefMaterial->setSpecularColorMap( specularMap ); 2127 | 2128 | dsDefMaterial->setSpecularStrength( specularFactor ); 2129 | 2130 | dsDefMaterial->setGlossinessStrength( shininess ); 2131 | dsDefMaterial->setGlossinessValueMap( shininessMap ); 2132 | 2133 | dsDefMaterial->setReflectionStrength( reflectionFactor ); 2134 | dsDefMaterial->setReflectionMap( reflectionMap ); 2135 | } 2136 | } 2137 | else if ( fbxPhong ) //DzPbrMaterial or DzUberIrayMaterial 2138 | { 2139 | // Because DzPbrMaterial is not in the public SDK, we attempt to use 2140 | // the meta-object to call the methods. If this fails, we attempt to 2141 | // find the properties by name and if found set their respective values. 2142 | 2143 | // use "setGlossyRoughness" double if using DzUberIrayMaterial 2144 | if ( !QMetaObject::invokeMethod( dsMaterial, 2145 | "setRoughness", Q_ARG( float, roughness ) ) ) 2146 | { 2147 | if ( DzFloatProperty* fProp = qobject_cast( dsMaterial->findProperty( "Glossy Roughness" ) ) ) 2148 | { 2149 | fProp->setValue( roughness ); 2150 | } 2151 | } 2152 | 2153 | //use "setMetallicity" double if using DzUberIrayMaterial 2154 | if ( !QMetaObject::invokeMethod( dsMaterial, 2155 | "setMetallicity", Q_ARG( float, metallicity ) ) ) 2156 | { 2157 | if ( DzFloatProperty* fProp = qobject_cast( dsMaterial->findProperty( "Metallic Weight" ) ) ) 2158 | { 2159 | fProp->setValue( metallicity ); 2160 | } 2161 | } 2162 | } 2163 | 2164 | m_dsMaterials.push_back( dsMaterial ); 2165 | 2166 | dsShape->addMaterial( dsMaterial ); 2167 | dsMesh->activateMaterial( dsMaterial->getName() ); 2168 | } 2169 | 2170 | matsAllSame = true; 2171 | for ( int i = 0, n = fbxMesh->GetElementMaterialCount(); i < n; i++ ) 2172 | { 2173 | const FbxGeometryElementMaterial* fbxMaterial = fbxMesh->GetElementMaterial( i ); 2174 | if ( fbxMaterial->GetMappingMode() == FbxGeometryElement::eByPolygon ) 2175 | { 2176 | matsAllSame = false; 2177 | break; 2178 | } 2179 | } 2180 | 2181 | if ( matsAllSame ) 2182 | { 2183 | for ( int i = 0, n = fbxMesh->GetElementMaterialCount(); i < n; i++ ) 2184 | { 2185 | const FbxGeometryElementMaterial* fbxMaterial = fbxMesh->GetElementMaterial( i ); 2186 | if ( fbxMaterial->GetMappingMode() == FbxGeometryElement::eAllSame ) 2187 | { 2188 | const int matIdx = fbxMaterial->GetIndexArray().GetAt( 0 ); 2189 | if ( matIdx >= 0 ) 2190 | { 2191 | dsMesh->activateMaterial( matIdx ); 2192 | break; 2193 | } 2194 | } 2195 | } 2196 | } 2197 | } 2198 | 2199 | #if !DZ_SDK_4_12_OR_GREATER 2200 | static void selectFacetsByIndexList( DzFacetMesh* dsMesh, DzFaceGroup* dsFaceGroup ) 2201 | { 2202 | const int nFacets = dsMesh->getNumFacets(); 2203 | const int* faceGrpIndices = dsFaceGroup->getIndicesPtr(); 2204 | unsigned char* facetFlags = dsMesh->getFacetFlagsPtr(); 2205 | for ( int i = 0, n = dsFaceGroup->count(); i < n; ++i ) 2206 | { 2207 | const int faceGrpIdx = faceGrpIndices[i]; 2208 | if ( faceGrpIdx >= nFacets ) 2209 | { 2210 | break; 2211 | } 2212 | 2213 | if ( facetFlags[faceGrpIdx] & DZ_HIDDEN_FACE_BIT ) 2214 | { 2215 | continue; 2216 | } 2217 | 2218 | facetFlags[faceGrpIdx] |= DZ_SELECTED_FACE_BIT; 2219 | } 2220 | } 2221 | #endif 2222 | 2223 | /** 2224 | Builds face groups, or polygon selection sets, from polygon selection set 2225 | data in the FBX. 2226 | 2227 | @param dsMeshNode The node that provides the mesh with the polygons we are 2228 | interested in. Used to validate that a given selection 2229 | set is intended for 'this' object. 2230 | @param dsMesh The facet mesh that we will alter the face group(s) of. 2231 | @param dsShape The shape to create a facet selection group on; depending 2232 | on the active options. 2233 | 2234 | @sa fbxImportMesh() 2235 | **/ 2236 | void DzFbxImporter::fbxImportPolygonSets( DzNode* dsMeshNode, DzFacetMesh* dsMesh, DzFacetShape* dsShape ) 2237 | { 2238 | if ( !m_includePolygonSets ) 2239 | { 2240 | return; 2241 | } 2242 | 2243 | const bool asFaceGroups = !m_includePolygonGroups; 2244 | 2245 | for ( int i = 0, n = m_fbxScene->GetMemberCount(); i < n; i++ ) 2246 | { 2247 | FbxSelectionSet* fbxSelectionSet = m_fbxScene->GetMember( i ); 2248 | if ( !fbxSelectionSet ) 2249 | { 2250 | continue; 2251 | } 2252 | 2253 | const QString fbxSelSetName( fbxSelectionSet->GetName() ); 2254 | QStringList fbxSelSetNameParts = fbxSelSetName.split( "__" ); 2255 | const QString dsFaceGroupName( fbxSelSetNameParts.first() ); 2256 | const QString dsMeshNodeName( fbxSelSetNameParts.last() ); 2257 | if ( dsMeshNodeName == dsFaceGroupName 2258 | || dsMeshNodeName != dsMeshNode->getName() ) 2259 | { 2260 | continue; 2261 | } 2262 | 2263 | FbxArray fbxSelectionNodeList; 2264 | FbxArray fbxDirectObjectList; 2265 | fbxSelectionSet->GetSelectionNodesAndDirectObjects( fbxSelectionNodeList, fbxDirectObjectList ); 2266 | 2267 | // directly connected objects 2268 | for ( int j = 0, m = fbxDirectObjectList.GetCount(); j < m; j++ ) 2269 | { 2270 | const FbxObject* fbxObject = fbxDirectObjectList[j]; 2271 | const QString str( fbxObject->GetName() ); 2272 | Q_UNUSED( str ); 2273 | } 2274 | 2275 | // selection nodes 2276 | for ( int j = 0, m = fbxSelectionNodeList.GetCount(); j < m; j++ ) 2277 | { 2278 | FbxSelectionNode* fbxSelectionNode = fbxSelectionNodeList[j]; 2279 | if ( !fbxSelectionNode ) 2280 | { 2281 | continue; 2282 | } 2283 | 2284 | FbxArray fbxFacetIndices; 2285 | fbxSelectionSet->GetFaceSelection( fbxSelectionNode, fbxFacetIndices ); 2286 | 2287 | if ( fbxFacetIndices.GetCount() < 1 ) 2288 | { 2289 | continue; 2290 | } 2291 | 2292 | if ( asFaceGroups ) 2293 | { 2294 | const bool created = dsMesh->createFaceGroup( dsFaceGroupName ); 2295 | Q_UNUSED( created ) 2296 | 2297 | const int numFacetIndices = fbxFacetIndices.GetCount(); 2298 | 2299 | // create a temporary list of facet indices to use for selection 2300 | DzTSharedPointer dsFaceGroup( new DzFaceGroup( dsFaceGroupName ) ); 2301 | dsFaceGroup->preSizeArray( numFacetIndices ); 2302 | for ( int k = 0; k < numFacetIndices; k++ ) 2303 | { 2304 | dsFaceGroup->addIndex( fbxFacetIndices.GetAt( k ) ); 2305 | } 2306 | 2307 | // use facet selection state to create face groups; 2308 | // doing it this way more easily handles exclusivity 2309 | #if DZ_SDK_4_12_OR_GREATER 2310 | dsMesh->beginFacetSelectionEdit(); 2311 | #else 2312 | // DzFacetMesh::beginFacetSelectionEdit() is not in the 4.5 SDK, 2313 | // so we attempt to use the meta-object to call the method - since 4.6.3.39 2314 | 2315 | bool im = QMetaObject::invokeMethod( dsMesh, "beginFacetSelectionEdit" ); 2316 | assert( im ); 2317 | #endif 2318 | 2319 | dsMesh->deselectAllFacets(); 2320 | 2321 | #if DZ_SDK_4_12_OR_GREATER 2322 | dsMesh->selectFacetsByIndexList( dsFaceGroup, true ); 2323 | #else 2324 | // DzFacetMesh::selectFacetsByIndexList() is not in the 4.5 SDK, 2325 | // so we attempt to use the meta-object to call the method - since 4.6.3.39. 2326 | // If that fails we fall back to doing it ourselves 2327 | 2328 | if ( !QMetaObject::invokeMethod( dsMesh, "selectFacetsByIndexList", 2329 | Q_ARG( const DzIndexList*, dsFaceGroup ), Q_ARG( bool, true) ) ) 2330 | { 2331 | selectFacetsByIndexList( dsMesh, dsFaceGroup ); 2332 | } 2333 | #endif 2334 | 2335 | dsMesh->addSelectedFacetsToGroup( dsFaceGroupName ); 2336 | dsMesh->deselectAllFacets(); 2337 | 2338 | #if DZ_SDK_4_12_OR_GREATER 2339 | dsMesh->finishFacetSelectionEdit(); 2340 | #else 2341 | // DzFacetMesh::beginFacetSelectionEdit() is not in the 4.5 SDK, 2342 | // so we attempt to use the meta-object to call the method - since 4.6.3.39 2343 | 2344 | im = QMetaObject::invokeMethod( dsMesh, "finishFacetSelectionEdit" ); 2345 | assert( im ); 2346 | #endif 2347 | } 2348 | else // as a selection group 2349 | { 2350 | #if DZ_SDK_4_12_OR_GREATER 2351 | DzSelectionGroup* dsSelectionGrp = dsShape->findFacetSelectionGroup( dsFaceGroupName, true ); 2352 | for ( int k = 0; k < fbxFacetIndices.GetCount(); k++ ) 2353 | { 2354 | dsSelectionGrp->addIndex( fbxFacetIndices.GetAt( k ) ); 2355 | } 2356 | #else 2357 | // DzSelectionGroup is not in the 4.5 SDK, but its superclass 2358 | // DzIndexList is and it provides DzIndexList::addIndex() 2359 | 2360 | // DzFacetShape::findFacetSelectionGroup() is not in the 4.5 SDK, 2361 | // so we attempt to use the meta-object to call the method - since 4.6.3.39 2362 | 2363 | DzIndexList* dsSelectionGrp = NULL; 2364 | if ( QMetaObject::invokeMethod( dsShape, "findFacetSelectionGroup", 2365 | Q_RETURN_ARG( DzIndexList*, dsSelectionGrp ), 2366 | Q_ARG( const QString&, dsFaceGroupName ), Q_ARG( bool, true ) ) ) 2367 | { 2368 | for ( int k = 0, p = fbxFacetIndices.GetCount(); k < p; k++ ) 2369 | { 2370 | dsSelectionGrp->addIndex( fbxFacetIndices.GetAt( k ) ); 2371 | } 2372 | } 2373 | #endif 2374 | } 2375 | } 2376 | } 2377 | 2378 | // clean up empty face groups 2379 | for ( int i = dsMesh->getNumFaceGroups() - 1; i >= 0; --i ) 2380 | { 2381 | DzFaceGroup* dsFaceGroup = dsMesh->getFaceGroup( i ); 2382 | if ( dsFaceGroup->count() > 0 ) 2383 | { 2384 | continue; 2385 | } 2386 | 2387 | #if DZ_SDK_4_12_OR_GREATER 2388 | const bool removed = dsMesh->removeFaceGroup( dsFaceGroup->getName() ); 2389 | Q_UNUSED( removed ) 2390 | #else 2391 | bool removed = false; 2392 | // DzFacetMesh::removeFaceGroup() is not in the 4.5 SDK, so we attempt 2393 | // to use the meta-object to call the method. If this fails, we attempt to 2394 | // use the deprecated method. 2395 | 2396 | if ( !QMetaObject::invokeMethod( dsMesh, "removeFaceGroup", 2397 | Q_RETURN_ARG( bool, removed ), Q_ARG( QString, dsFaceGroup->getName() )) ) 2398 | { 2399 | removed = dsMesh->removeFacetGroup( dsFaceGroup->getName() ); 2400 | } 2401 | Q_UNUSED( removed ) 2402 | #endif 2403 | } 2404 | } 2405 | 2406 | /** 2407 | **/ 2408 | void DzFbxImporter::updateSelectionMap( Node* node ) 2409 | { 2410 | const QString fbxSelSetName = m_nodeFaceGroupMap.value( node ); 2411 | if ( fbxSelSetName.isEmpty() ) 2412 | { 2413 | return; 2414 | } 2415 | 2416 | QStringList fbxSelSetNameParts = fbxSelSetName.split( "__" ); 2417 | const QString dsFaceGroupName( fbxSelSetNameParts.first() ); 2418 | const QString dsMeshNodeName( fbxSelSetNameParts.last() ); 2419 | 2420 | DzBone* dsBone = qobject_cast( node->dsNode ); 2421 | if ( !dsBone ) 2422 | { 2423 | return; 2424 | } 2425 | 2426 | DzSkeleton* dsSkeleton = qobject_cast( dsBone->getSkeleton() ); 2427 | if ( !dsSkeleton ) 2428 | { 2429 | return; 2430 | } 2431 | 2432 | if ( dsSkeleton->getName() != dsMeshNodeName ) 2433 | { 2434 | return; 2435 | } 2436 | 2437 | const DzObject* dsObject = dsSkeleton->getObject(); 2438 | if ( !dsObject ) 2439 | { 2440 | return; 2441 | } 2442 | 2443 | const DzShape* dsShape = dsObject->getCurrentShape(); 2444 | if ( !dsShape ) 2445 | { 2446 | return; 2447 | } 2448 | 2449 | const DzFacetMesh* dsMesh = qobject_cast( dsShape->getGeometry() ); 2450 | if ( !dsMesh ) 2451 | { 2452 | return; 2453 | } 2454 | 2455 | if ( !dsMesh->findFaceGroup( dsFaceGroupName ) ) 2456 | { 2457 | return; 2458 | } 2459 | 2460 | DzSelectionMap* dsSelectionMap = dsSkeleton->getSelectionMap(); 2461 | if ( !dsSelectionMap ) 2462 | { 2463 | dsSelectionMap = new DzSelectionMap(); 2464 | dsSkeleton->setSelectionMap( dsSelectionMap ); 2465 | } 2466 | 2467 | dsSelectionMap->addPair( dsFaceGroupName, dsBone ); 2468 | 2469 | dsSkeleton->setDrawGLBones( false ); 2470 | } 2471 | 2472 | /** 2473 | **/ 2474 | void DzFbxImporter::fbxImportFaces( FbxMesh* fbxMesh, DzFacetMesh* dsMesh, bool matsAllSame, QMap, int> &edgeMap ) 2475 | { 2476 | int numEdges = 0; 2477 | 2478 | const int numPolygons = fbxMesh->GetPolygonCount(); 2479 | 2480 | const FbxGeometryElementPolygonGroup* fbxPolygonGroup = m_includePolygonGroups ? 2481 | fbxMesh->GetElementPolygonGroup( 0 ) : NULL; 2482 | 2483 | // check whether we have compatible polygon group info; 2484 | // count is 0 since FBX SDK 2020.0; 2485 | // count is as expected with FBX SDK 2019.5 and prior 2486 | const bool compatPolyGroup = fbxPolygonGroup && numPolygons == fbxPolygonGroup->GetIndexArray().GetCount(); 2487 | 2488 | int curGroupIdx = -1; 2489 | for ( int polyIdx = 0; polyIdx < numPolygons; polyIdx++ ) 2490 | { 2491 | // active material group 2492 | if ( !matsAllSame ) 2493 | { 2494 | for ( int matElemIdx = 0, numMatElements = fbxMesh->GetElementMaterialCount(); 2495 | matElemIdx < numMatElements; matElemIdx++ ) 2496 | { 2497 | const FbxGeometryElementMaterial* fbxMaterial = fbxMesh->GetElementMaterial( matElemIdx ); 2498 | const int polyMatIdx = fbxMaterial->GetIndexArray().GetAt( polyIdx ); 2499 | if ( polyMatIdx >= 0 ) 2500 | { 2501 | dsMesh->activateMaterial( polyMatIdx ); 2502 | break; 2503 | } 2504 | } 2505 | } 2506 | 2507 | // active face group 2508 | if ( compatPolyGroup ) 2509 | { 2510 | const int groupIdx = fbxPolygonGroup->GetIndexArray().GetAt( polyIdx ); 2511 | if ( groupIdx != curGroupIdx ) 2512 | { 2513 | curGroupIdx = groupIdx; 2514 | dsMesh->activateFaceGroup( "fbx_polygonGroup_" % QString::number( groupIdx ) ); 2515 | } 2516 | } 2517 | 2518 | DzFacet face; 2519 | 2520 | // facet vertices 2521 | int triFanRoot = -1; 2522 | for ( int polyVertIdx = 0, numPolyVerts = fbxMesh->GetPolygonSize( polyIdx ); 2523 | polyVertIdx < numPolyVerts; polyVertIdx++ ) 2524 | { 2525 | // quads, tris, lines 2526 | if ( numPolyVerts <= 4 ) 2527 | { 2528 | face.m_vertIdx[polyVertIdx] = fbxMesh->GetPolygonVertex( polyIdx, polyVertIdx ); 2529 | face.m_normIdx[polyVertIdx] = face.m_vertIdx[polyVertIdx]; 2530 | 2531 | // facet UVs 2532 | for ( int uvElemIdx = 0, numUvElems = fbxMesh->GetElementUVCount(); 2533 | uvElemIdx < numUvElems; uvElemIdx++ ) 2534 | { 2535 | const FbxGeometryElementUV* fbxGeomUv = fbxMesh->GetElementUV( uvElemIdx ); 2536 | switch ( fbxGeomUv->GetMappingMode() ) 2537 | { 2538 | case FbxGeometryElement::eByControlPoint: 2539 | switch ( fbxGeomUv->GetReferenceMode() ) 2540 | { 2541 | case FbxGeometryElement::eDirect: 2542 | face.m_uvwIdx[polyVertIdx] = face.m_vertIdx[polyVertIdx]; 2543 | break; 2544 | case FbxGeometryElement::eIndexToDirect: 2545 | face.m_uvwIdx[polyVertIdx] = fbxGeomUv->GetIndexArray().GetAt( face.m_vertIdx[polyVertIdx] ); 2546 | break; 2547 | default: 2548 | break; 2549 | } 2550 | break; 2551 | case FbxGeometryElement::eByPolygonVertex: 2552 | face.m_uvwIdx[polyVertIdx] = fbxMesh->GetTextureUVIndex( polyIdx, polyVertIdx ); 2553 | break; 2554 | default: 2555 | break; 2556 | } 2557 | 2558 | // only do the first UV set 2559 | break; 2560 | } 2561 | 2562 | if ( polyVertIdx == numPolyVerts - 1 ) 2563 | { 2564 | dsMesh->addFacet( face.m_vertIdx, face.m_uvwIdx ); 2565 | } 2566 | } 2567 | // n-gons 2568 | else if ( polyVertIdx >= 2 ) 2569 | { 2570 | const bool isRoot = polyVertIdx == 2; 2571 | 2572 | face.m_vertIdx[0] = fbxMesh->GetPolygonVertex( polyIdx, 0 ); 2573 | face.m_vertIdx[1] = fbxMesh->GetPolygonVertex( polyIdx, polyVertIdx - 1 ); 2574 | face.m_vertIdx[2] = fbxMesh->GetPolygonVertex( polyIdx, polyVertIdx ); 2575 | face.m_vertIdx[3] = -1; 2576 | face.m_normIdx[0] = face.m_vertIdx[0]; 2577 | face.m_normIdx[1] = face.m_vertIdx[1]; 2578 | face.m_normIdx[2] = face.m_vertIdx[2]; 2579 | face.m_normIdx[3] = face.m_vertIdx[3]; 2580 | 2581 | if ( isRoot ) 2582 | { 2583 | triFanRoot = dsMesh->getNumFacets(); 2584 | } 2585 | 2586 | #if DZ_SDK_4_12_OR_GREATER 2587 | face.setTriFanRoot( triFanRoot ); 2588 | #else 2589 | // DzFacet::setTriFanRoot() is not in the 4.5 SDK, and DzFacet 2590 | // is not derived from QObject, so we must modify the member 2591 | // directly. 2592 | 2593 | face.m_vertIdx[3] = -(triFanRoot + 2); 2594 | #endif 2595 | 2596 | if ( isRoot ) 2597 | { 2598 | #if DZ_SDK_4_12_OR_GREATER 2599 | face.setTriFanCount( numPolyVerts - 2 ); 2600 | #else 2601 | // DzFacet::setTriFanCount() is not in the 4.5 SDK, and DzFacet 2602 | // is not derived from QObject, so we must modify the member 2603 | // directly. 2604 | 2605 | face.m_edges[3] = -numPolyVerts; 2606 | #endif 2607 | } 2608 | else 2609 | { 2610 | #if DZ_SDK_4_12_OR_GREATER 2611 | face.clearTriFanCount(); 2612 | #else 2613 | // DzFacet::clearTriFanCount() is not in the 4.5 SDK, and DzFacet 2614 | // is not derived from QObject, so we must modify the member 2615 | // directly. 2616 | 2617 | face.m_edges[3] = -1; 2618 | #endif 2619 | } 2620 | 2621 | // facet UVs 2622 | for ( int uvElemIdx = 0, numUvElems = fbxMesh->GetElementUVCount(); 2623 | uvElemIdx < numUvElems; uvElemIdx++ ) 2624 | { 2625 | const FbxGeometryElementUV* fbxGeomUv = fbxMesh->GetElementUV( uvElemIdx ); 2626 | switch ( fbxGeomUv->GetMappingMode() ) 2627 | { 2628 | case FbxGeometryElement::eByControlPoint: 2629 | switch ( fbxGeomUv->GetReferenceMode() ) 2630 | { 2631 | case FbxGeometryElement::eDirect: 2632 | face.m_uvwIdx[0] = face.m_vertIdx[0]; 2633 | face.m_uvwIdx[1] = face.m_vertIdx[polyVertIdx - 1]; 2634 | face.m_uvwIdx[2] = face.m_vertIdx[polyVertIdx]; 2635 | face.m_uvwIdx[3] = -1; 2636 | break; 2637 | case FbxGeometryElement::eIndexToDirect: 2638 | face.m_uvwIdx[0] = fbxGeomUv->GetIndexArray().GetAt( face.m_vertIdx[0] ); 2639 | face.m_uvwIdx[1] = fbxGeomUv->GetIndexArray().GetAt( face.m_vertIdx[polyVertIdx - 1] ); 2640 | face.m_uvwIdx[2] = fbxGeomUv->GetIndexArray().GetAt( face.m_vertIdx[polyVertIdx] ); 2641 | face.m_uvwIdx[3] = -1; 2642 | break; 2643 | default: 2644 | break; 2645 | } 2646 | break; 2647 | case FbxGeometryElement::eByPolygonVertex: 2648 | face.m_uvwIdx[0] = fbxMesh->GetTextureUVIndex( polyIdx, polyVertIdx ); 2649 | face.m_uvwIdx[1] = fbxMesh->GetTextureUVIndex( polyIdx, polyVertIdx - 1 ); 2650 | face.m_uvwIdx[2] = fbxMesh->GetTextureUVIndex( polyIdx, polyVertIdx ); 2651 | face.m_uvwIdx[3] = -1; 2652 | break; 2653 | default: 2654 | break; 2655 | } 2656 | 2657 | // only do the first UV set 2658 | break; 2659 | } 2660 | 2661 | #if DZ_SDK_4_12_OR_GREATER 2662 | dsMesh->addFacet( face ); 2663 | #else 2664 | // DzFacetMesh::addFacet() is not in the 4.5 SDK, so we attempt 2665 | // to use the meta-object to call the method. 2666 | 2667 | bool im = QMetaObject::invokeMethod( dsMesh, "addFacet", 2668 | Q_ARG( const DzFacet &, face ) ); 2669 | assert( im ); 2670 | #endif 2671 | 2672 | if ( isRoot ) 2673 | { 2674 | #if DZ_SDK_4_12_OR_GREATER 2675 | dsMesh->incrementNgons(); 2676 | #else 2677 | // DzFacetMesh::incrementNgons() is not in the 4.5 SDK, so 2678 | // we attempt to use the meta-object to call the method. 2679 | 2680 | bool im = QMetaObject::invokeMethod( dsMesh, "incrementNgons" ); 2681 | assert( im ); 2682 | #endif 2683 | } 2684 | } 2685 | 2686 | 2687 | { 2688 | const int polyVertNextIdx = (polyVertIdx + 1) % numPolyVerts; 2689 | 2690 | const int edgeVertA = fbxMesh->GetPolygonVertex( polyIdx, polyVertIdx ); 2691 | const int edgeVertB = fbxMesh->GetPolygonVertex( polyIdx, polyVertNextIdx ); 2692 | QPair edgeVertPair( qMin( edgeVertA, edgeVertB ), qMax( edgeVertA, edgeVertB ) ); 2693 | if ( !edgeMap.contains( edgeVertPair ) ) 2694 | { 2695 | edgeMap[edgeVertPair] = numEdges; 2696 | numEdges++; 2697 | } 2698 | } 2699 | } 2700 | } 2701 | } 2702 | 2703 | /** 2704 | **/ 2705 | void DzFbxImporter::fbxImportSubdEdgeWeights( FbxMesh* fbxMesh, DzFacetMesh* dsMesh, QMap, int> edgeMap, bool &enableSubd ) 2706 | { 2707 | for ( int i = 0, n = fbxMesh->GetElementEdgeCreaseCount(); i < n; i++ ) 2708 | { 2709 | const FbxGeometryElementCrease* fbxSubdEdgeCrease = fbxMesh->GetElementEdgeCrease( i ); 2710 | const int numCreases = fbxSubdEdgeCrease->GetDirectArray().GetCount(); 2711 | Q_UNUSED( numCreases ) 2712 | 2713 | QMap< QPair, int >::iterator edgeMapIt; 2714 | for ( edgeMapIt = edgeMap.begin(); edgeMapIt != edgeMap.end(); ++edgeMapIt ) 2715 | { 2716 | const int edgeIdx = edgeMapIt.value(); 2717 | const float weight = fbxSubdEdgeCrease->GetDirectArray().GetAt( edgeIdx ); 2718 | const int edgeVertA = edgeMapIt.key().first; 2719 | const int edgeVertB = edgeMapIt.key().second; 2720 | if ( weight > 0 ) 2721 | { 2722 | enableSubd = true; 2723 | #if DZ_SDK_4_12_OR_GREATER 2724 | dsMesh->setEdgeWeight( edgeVertA, edgeVertB, weight ); 2725 | #else 2726 | // DzFacetMesh::setEdgeWeight() is not in the 4.5 SDK, so we 2727 | // attempt to use the meta-object to call the method. 2728 | 2729 | bool im = QMetaObject::invokeMethod( dsMesh, "setEdgeWeight", 2730 | Q_ARG( int, edgeVertA ), Q_ARG( int, edgeVertB ), Q_ARG( int, weight ) ); 2731 | assert( im ); 2732 | #endif 2733 | } 2734 | } 2735 | 2736 | // only do the first 2737 | break; 2738 | } 2739 | } 2740 | 2741 | /** 2742 | **/ 2743 | DzWeightMapPtr DzFbxImporter::fbxImportSkinningBlendWeights( int numVertices, const FbxSkin* fbxSkin ) 2744 | { 2745 | if ( numVertices < 1 2746 | || !fbxSkin 2747 | || fbxSkin->GetSkinningType() != FbxSkin::eBlend ) 2748 | { 2749 | return NULL; 2750 | } 2751 | 2752 | const int numBlendIndices = fbxSkin->GetControlPointIndicesCount(); 2753 | const int* fbxBlendIndices = fbxSkin->GetControlPointIndices(); 2754 | if ( numBlendIndices <= 0 || !fbxBlendIndices ) 2755 | { 2756 | return NULL; 2757 | } 2758 | 2759 | DzWeightMapPtr dsBlendWeights = new DzWeightMap( numVertices, "Blend Weights" ); 2760 | unsigned short* dsWeightValues = dsBlendWeights->getWeights(); 2761 | for ( int bwIdx = 0; bwIdx < numBlendIndices; ++bwIdx ) 2762 | { 2763 | const int idx = fbxBlendIndices[bwIdx]; 2764 | if ( idx > numVertices ) 2765 | { 2766 | continue; 2767 | } 2768 | 2769 | const double fbxBlendWeight = fbxSkin->GetControlPointBlendWeights()[bwIdx]; 2770 | dsWeightValues[idx] = DZ_USHORT_MAX * fbxBlendWeight; 2771 | } 2772 | 2773 | #if DZ_SDK_4_12_OR_GREATER 2774 | dsBlendWeights->reduceWeightMemory(); 2775 | #endif 2776 | 2777 | return dsBlendWeights; 2778 | } 2779 | 2780 | /** 2781 | **/ 2782 | void DzFbxImporter::fbxImportMorph( FbxBlendShape* fbxBlendShape, DzObject* dsObject, int numVertices, FbxVector4* fbxVertices ) 2783 | { 2784 | if ( !fbxBlendShape 2785 | || !dsObject 2786 | || numVertices < 1 ) 2787 | { 2788 | return; 2789 | } 2790 | 2791 | DzPnt3* values = new DzPnt3[numVertices]; 2792 | 2793 | const int numBlendShapeChannels = fbxBlendShape->GetBlendShapeChannelCount(); 2794 | 2795 | DzProgress progress( "Morphs", numBlendShapeChannels ); 2796 | for ( int blendShapeChanIdx = 0; blendShapeChanIdx < numBlendShapeChannels; blendShapeChanIdx++ ) 2797 | { 2798 | FbxBlendShapeChannel* fbxBlendChannel = fbxBlendShape->GetBlendShapeChannel( blendShapeChanIdx ); 2799 | 2800 | DzMorph* dsMorph = new DzMorph; 2801 | dsMorph->setName( fbxBlendChannel->GetName() ); 2802 | DzMorphDeltas* dsDeltas = dsMorph->getDeltas(); 2803 | 2804 | DzFloatProperty* morphControl = NULL; 2805 | #if DZ_SDK_4_12_OR_GREATER 2806 | morphControl = dsMorph->getValueControl(); 2807 | #else 2808 | // DzMorph::getValueControl() is not in the 4.5 SDK, but DzMorph::getValueChannel() 2809 | // was, so we use the previous name. 2810 | 2811 | morphControl = dsMorph->getValueChannel(); 2812 | #endif 2813 | 2814 | applyFbxCurve( fbxBlendChannel->DeformPercent.GetCurve( m_fbxAnimLayer ), morphControl, 0.01 ); 2815 | 2816 | for ( int vertIdx = 0; vertIdx < numVertices; vertIdx++ ) 2817 | { 2818 | values[vertIdx][0] = 0; 2819 | values[vertIdx][1] = 0; 2820 | values[vertIdx][2] = 0; 2821 | } 2822 | 2823 | for ( int tgtShapeIdx = 0, numTgtShapes = fbxBlendChannel->GetTargetShapeCount(); 2824 | tgtShapeIdx < numTgtShapes; tgtShapeIdx++ ) 2825 | { 2826 | FbxShape* fbxTargetShape = fbxBlendChannel->GetTargetShape( tgtShapeIdx ); 2827 | FbxVector4* fbxTargetShapeVerts = fbxTargetShape->GetControlPoints(); 2828 | int* fbxTgtShapeVertIndices = fbxTargetShape->GetControlPointIndices(); 2829 | //double weight = fbxBlendChannel->GetTargetShapeFullWeights()[k]; 2830 | 2831 | if ( fbxTgtShapeVertIndices ) 2832 | { 2833 | for ( int tgtShapeVertIndicesIdx = 0, numTgtShapeVertIndices = fbxTargetShape->GetControlPointIndicesCount(); 2834 | tgtShapeVertIndicesIdx < numTgtShapeVertIndices; tgtShapeVertIndicesIdx++ ) 2835 | { 2836 | const int vertIdx = fbxTgtShapeVertIndices[tgtShapeVertIndicesIdx]; 2837 | values[vertIdx][0] = fbxTargetShapeVerts[vertIdx][0] - fbxVertices[vertIdx][0]; 2838 | values[vertIdx][1] = fbxTargetShapeVerts[vertIdx][1] - fbxVertices[vertIdx][1]; 2839 | values[vertIdx][2] = fbxTargetShapeVerts[vertIdx][2] - fbxVertices[vertIdx][2]; 2840 | } 2841 | } 2842 | else 2843 | { 2844 | for ( int vertIdx = 0, numTgtShapeVerts = fbxTargetShape->GetControlPointsCount(); 2845 | vertIdx < numTgtShapeVerts; vertIdx++ ) 2846 | { 2847 | values[vertIdx][0] = fbxTargetShapeVerts[vertIdx][0] - fbxVertices[vertIdx][0]; 2848 | values[vertIdx][1] = fbxTargetShapeVerts[vertIdx][1] - fbxVertices[vertIdx][1]; 2849 | values[vertIdx][2] = fbxTargetShapeVerts[vertIdx][2] - fbxVertices[vertIdx][2]; 2850 | } 2851 | } 2852 | } 2853 | 2854 | DzIntArray indexes; 2855 | DzTArray deltas; 2856 | for ( int vertIdx = 0; vertIdx < numVertices; vertIdx++ ) 2857 | { 2858 | if ( values[vertIdx][0] != 0 || values[vertIdx][1] != 0 || values[vertIdx][2] != 0 ) 2859 | { 2860 | indexes.append( vertIdx ); 2861 | deltas.append( DzVec3( values[vertIdx][0], values[vertIdx][1], values[vertIdx][2] ) ); 2862 | } 2863 | } 2864 | dsDeltas->addDeltas( indexes, deltas, false ); 2865 | dsObject->addModifier( dsMorph ); 2866 | 2867 | progress.step(); 2868 | } 2869 | 2870 | delete[] values; 2871 | } 2872 | 2873 | /** 2874 | **/ 2875 | void DzFbxImporter::fbxImportMeshModifiers( Node* node, FbxMesh* fbxMesh, DzObject* dsObject, DzFigure* dsFigure, int numVertices, FbxVector4* fbxVertices ) 2876 | { 2877 | for ( int deformerIdx = 0, numDeformers = fbxMesh->GetDeformerCount(); deformerIdx < numDeformers; deformerIdx++ ) 2878 | { 2879 | FbxDeformer* fbxDeformer = fbxMesh->GetDeformer( deformerIdx ); 2880 | 2881 | // skin binding 2882 | if ( FbxSkin* fbxSkin = FbxCast( fbxDeformer ) ) 2883 | { 2884 | if ( !dsFigure ) 2885 | { 2886 | continue; 2887 | } 2888 | 2889 | Skinning skinning; 2890 | skinning.node = node; 2891 | skinning.fbxSkin = fbxSkin; 2892 | skinning.dsFigure = dsFigure; 2893 | skinning.numVertices = numVertices; 2894 | skinning.blendWeights = fbxImportSkinningBlendWeights( numVertices, fbxSkin ); 2895 | m_skins.push_back( skinning ); 2896 | } 2897 | // morphs 2898 | else if ( FbxBlendShape* fbxBlendShape = FbxCast( fbxDeformer ) ) 2899 | { 2900 | fbxImportMorph( fbxBlendShape, dsObject, numVertices, fbxVertices ); 2901 | } 2902 | } 2903 | } 2904 | 2905 | /** 2906 | **/ 2907 | void DzFbxImporter::fbxImportMesh( Node* node, FbxNode* fbxNode, DzNode* dsMeshNode ) 2908 | { 2909 | FbxMesh* fbxMesh = fbxNode->GetMesh(); 2910 | 2911 | const QString dsName = dsMeshNode ? dsMeshNode->getName() : fbxNode->GetName(); 2912 | 2913 | DzObject* dsObject = new DzObject(); 2914 | dsObject->setName( !dsName.isEmpty() ? dsName : "object" ); 2915 | 2916 | DzFacetMesh* dsMesh = new DzFacetMesh(); 2917 | dsMesh->setName( !dsName.isEmpty() ? dsName : "geometry" ); 2918 | 2919 | #if DZ_SDK_4_12_OR_GREATER 2920 | DzFacetShape* dsShape = new DzGraftingFigureShape(); 2921 | #else 2922 | // DzGraftingFigureShape is not in the 4.5 SDK, but if the version of the 2923 | // application has the factory for the class we can use it to create an 2924 | // instance or fallback to the base class that is in the 4.5 SDK 2925 | 2926 | DzFacetShape* dsShape; 2927 | if ( const DzClassFactory* factory = dzApp->findClassFactory( "DzGraftingFigureShape" ) ) 2928 | { 2929 | dsShape = qobject_cast( factory->createInstance() ); 2930 | } 2931 | else 2932 | { 2933 | dsShape = new DzFacetShape(); 2934 | } 2935 | #endif 2936 | dsShape->setName( !dsName.isEmpty() ? dsName : "shape" ); 2937 | 2938 | DzFigure* dsFigure = qobject_cast( dsMeshNode ); 2939 | 2940 | DzVec3 offset( 0, 0, 0 ); 2941 | if ( dsFigure ) 2942 | { 2943 | offset = dsFigure->getOrigin(); 2944 | } 2945 | 2946 | // begin the edit 2947 | dsMesh->beginEdit(); 2948 | 2949 | const int numVertices = fbxMesh->GetControlPointsCount(); 2950 | FbxVector4* fbxVertices = fbxMesh->GetControlPoints(); 2951 | fbxImportVertices( numVertices, fbxVertices, dsMesh, offset ); 2952 | 2953 | fbxImportUVs( fbxMesh, dsMesh ); 2954 | 2955 | bool enableSubd = false; 2956 | fbxImportSubdVertexWeights( fbxMesh, dsMesh, enableSubd ); 2957 | 2958 | bool matsAllSame; 2959 | fbxImportMaterials( fbxNode, fbxMesh, dsMesh, dsShape, matsAllSame ); 2960 | 2961 | QMap< QPair< int, int >, int > edgeMap; 2962 | fbxImportFaces( fbxMesh, dsMesh, matsAllSame, edgeMap ); 2963 | 2964 | fbxImportSubdEdgeWeights( fbxMesh, dsMesh, edgeMap, enableSubd ); 2965 | 2966 | // end the edit 2967 | dsMesh->finishEdit(); 2968 | 2969 | dsShape->setFacetMesh( dsMesh ); 2970 | 2971 | setSubdEnabled( enableSubd, dsMesh, dsShape ); 2972 | 2973 | dsObject->addShape( dsShape ); 2974 | dsMeshNode->setObject( dsObject ); 2975 | 2976 | fbxImportPolygonSets( dsMeshNode, dsMesh, dsShape ); 2977 | 2978 | fbxImportMeshModifiers( node, fbxMesh, dsObject, dsFigure, numVertices, fbxVertices ); 2979 | } 2980 | 2981 | /** 2982 | **/ 2983 | void DzFbxImporter::setSubdEnabled( bool onOff, DzFacetMesh* dsMesh, DzFacetShape* dsShape ) 2984 | { 2985 | if ( !onOff ) 2986 | { 2987 | return; 2988 | } 2989 | 2990 | dsMesh->enableSubDivision( true ); 2991 | 2992 | if ( DzEnumProperty* lodControl = dsShape->getLODControl() ) 2993 | { 2994 | lodControl->setValue( lodControl->getNumItems() - 1 ); //set to high res 2995 | lodControl->setDefaultValue( lodControl->getNumItems() - 1 ); //set to high res 2996 | } 2997 | } 2998 | 2999 | /** 3000 | **/ 3001 | void DzFbxImporter::applyFbxCurve( FbxAnimCurve* fbxCurve, DzFloatProperty* dsProperty, double scale ) 3002 | { 3003 | if ( !fbxCurve || !dsProperty ) 3004 | { 3005 | return; 3006 | } 3007 | 3008 | dsProperty->deleteAllKeys(); 3009 | 3010 | for ( int i = 0; i < fbxCurve->KeyGetCount(); i++ ) 3011 | { 3012 | const double fbxTime = fbxCurve->KeyGetTime( i ).GetSecondDouble(); 3013 | const double fbxValue = fbxCurve->KeyGetValue( i ); 3014 | DzTime dsTime = static_cast< DzTime >((fbxTime * DZ_TICKS_PER_SECOND) + 0.5f); //round to nearest tick 3015 | m_dsEndTime = qMax( m_dsEndTime, dsTime ); 3016 | 3017 | dsProperty->setValue( dsTime, fbxValue * scale ); 3018 | } 3019 | } 3020 | 3021 | /////////////////////////////////////////////////////////////////////// 3022 | // DzFbxImportFrame 3023 | /////////////////////////////////////////////////////////////////////// 3024 | 3025 | struct DzFbxImportFrame::Data 3026 | { 3027 | Data( DzFbxImporter* importer ) : 3028 | m_importer( importer ), 3029 | m_includeRotationLimitsCbx( NULL ), 3030 | m_includeAnimationCbx( NULL ), 3031 | m_animationTakeCmb( NULL ), 3032 | m_includePolygonSetsCbx( NULL ), 3033 | m_includePolygonGroupsCbx( NULL ), 3034 | m_studioNodeNameLabelCbx( NULL ), 3035 | m_studioPresentationCbx( NULL ), 3036 | m_studioSelectionMapCbx( NULL ), 3037 | m_studioSceneIDsCbx( NULL ) 3038 | {} 3039 | 3040 | DzFbxImporter* m_importer; 3041 | 3042 | QCheckBox* m_includeRotationLimitsCbx; 3043 | QCheckBox* m_includeAnimationCbx; 3044 | QComboBox* m_animationTakeCmb; 3045 | 3046 | QCheckBox* m_includePolygonSetsCbx; 3047 | QCheckBox* m_includePolygonGroupsCbx; 3048 | 3049 | QCheckBox* m_studioNodeNameLabelCbx; 3050 | QCheckBox* m_studioPresentationCbx; 3051 | QCheckBox* m_studioSelectionMapCbx; 3052 | QCheckBox* m_studioSceneIDsCbx; 3053 | }; 3054 | 3055 | namespace 3056 | { 3057 | 3058 | QGroupBox* createCollapsibleGroupBox( const QString &title, const QString &basename, bool collapsed = false ) 3059 | { 3060 | #if DZ_SDK_4_12_OR_GREATER 3061 | DzCollapsibleGroupBox* groupBox = new DzCollapsibleGroupBox( title ); 3062 | groupBox->setObjectName( basename % "GBox" ); 3063 | groupBox->setCollapsed( collapsed ); 3064 | #else 3065 | QGroupBox* groupBox = NULL; 3066 | if ( const DzClassFactory* factory = dzApp->findClassFactory( "DzCollapsibleGroupBox" ) ) 3067 | { 3068 | groupBox = qobject_cast( factory->createInstance() ); 3069 | } 3070 | 3071 | if ( !groupBox ) 3072 | { 3073 | groupBox = new QGroupBox(); 3074 | } 3075 | 3076 | groupBox->setObjectName( basename % "GBox" ); 3077 | groupBox->setTitle( title ); 3078 | #endif //DZ_SDK_4_12_OR_GREATER 3079 | 3080 | return groupBox; 3081 | } 3082 | 3083 | QScrollArea* createScrollableWidget( QWidget* widgetToScroll, int margin, int spacing, const QString &nameBase ) 3084 | { 3085 | QWidget* scrollableWgt = new QWidget(); 3086 | scrollableWgt->setObjectName( nameBase % "ScrollWgt" ); 3087 | 3088 | QVBoxLayout* scrollableLyt = new QVBoxLayout(); 3089 | scrollableLyt->setMargin( margin ); 3090 | scrollableLyt->setSpacing( spacing ); 3091 | 3092 | scrollableLyt->addWidget( widgetToScroll ); 3093 | 3094 | scrollableLyt->addStretch(); 3095 | 3096 | scrollableWgt->setLayout( scrollableLyt ); 3097 | 3098 | QScrollArea* scrollArea = new QScrollArea(); 3099 | scrollArea->setObjectName( nameBase % "ScrollArea" ); 3100 | scrollArea->setWidgetResizable( true ); 3101 | scrollArea->setWidget( scrollableWgt ); 3102 | 3103 | return scrollArea; 3104 | } 3105 | 3106 | const char* c_none = QT_TRANSLATE_NOOP( "DzFbxImportFrame", "" ); 3107 | 3108 | } //namespace 3109 | 3110 | /** 3111 | **/ 3112 | DzFbxImportFrame::DzFbxImportFrame( DzFbxImporter* importer ) : 3113 | DzFileIOFrame( tr( "FBX Import Options" ) ), m_data( new Data( importer ) ) 3114 | { 3115 | const QString name( "FbxImport" ); 3116 | 3117 | const int margin = style()->pixelMetric( DZ_PM_GeneralMargin ); 3118 | const int btnHeight = style()->pixelMetric( DZ_PM_ButtonHeight ); 3119 | 3120 | QVector leftLabels; 3121 | leftLabels.reserve( 10 ); 3122 | 3123 | QVBoxLayout* mainLyt = new QVBoxLayout(); 3124 | mainLyt->setSpacing( margin ); 3125 | mainLyt->setMargin( margin ); 3126 | 3127 | // Format 3128 | QGroupBox* formatGBox = new QGroupBox( tr( "Format :" ) ); 3129 | formatGBox->setObjectName( name % "FormatGBox" ); 3130 | 3131 | QGridLayout* formatLyt = new QGridLayout(); 3132 | formatLyt->setSpacing( margin ); 3133 | formatLyt->setMargin( margin ); 3134 | formatLyt->setColumnStretch( 1, 1 ); 3135 | 3136 | int row = 0; 3137 | 3138 | QLabel* lbl = new QLabel( tr( "Version:" ) ); 3139 | lbl->setObjectName( name % "FileVersionLbl" ); 3140 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3141 | formatLyt->addWidget( lbl, row, 0 ); 3142 | leftLabels.push_back( lbl ); 3143 | 3144 | lbl = new QLabel( importer->getFileVersion() ); 3145 | lbl->setObjectName( name % "FileVersionValueLbl" ); 3146 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3147 | formatLyt->addWidget( lbl, row++, 1 ); 3148 | 3149 | lbl = new QLabel( tr( "Creator:" ) ); 3150 | lbl->setObjectName( name % "FileCreatorLbl" ); 3151 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3152 | formatLyt->addWidget( lbl, row, 0 ); 3153 | leftLabels.push_back( lbl ); 3154 | 3155 | lbl = new QLabel( importer->getFileCreator() ); 3156 | lbl->setObjectName( name % "FileCreatorValueLbl" ); 3157 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3158 | formatLyt->addWidget( lbl, row++, 1 ); 3159 | 3160 | formatGBox->setLayout( formatLyt ); 3161 | 3162 | mainLyt->addWidget( formatGBox ); 3163 | 3164 | 3165 | // Scene Info 3166 | QGroupBox* sceneInfoGBox = createCollapsibleGroupBox( tr( "Scene :" ), name % "SceneInfo", true ); 3167 | 3168 | QGridLayout* sceneInfoLyt = new QGridLayout(); 3169 | sceneInfoLyt->setSpacing( margin ); 3170 | sceneInfoLyt->setMargin( margin ); 3171 | sceneInfoLyt->setColumnStretch( 1, 1 ); 3172 | 3173 | row = 0; 3174 | 3175 | const QString sceneAuthor = importer->getSceneAuthor(); 3176 | if ( !sceneAuthor.isEmpty() ) 3177 | { 3178 | lbl = new QLabel( tr( "Author:" ) ); 3179 | lbl->setObjectName( name % "SceneAuthorLbl" ); 3180 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3181 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3182 | leftLabels.push_back( lbl ); 3183 | 3184 | lbl = new QLabel( sceneAuthor ); 3185 | lbl->setObjectName( name % "SceneAuthorValueLbl" ); 3186 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3187 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3188 | } 3189 | 3190 | const QString sceneTitle = importer->getSceneTitle(); 3191 | if ( !sceneTitle.isEmpty() ) 3192 | { 3193 | lbl = new QLabel( tr( "Title:" ) ); 3194 | lbl->setObjectName( name % "SceneTitleLbl" ); 3195 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3196 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3197 | leftLabels.push_back( lbl ); 3198 | 3199 | lbl = new QLabel( sceneTitle ); 3200 | lbl->setObjectName( name % "SceneTitleValueLbl" ); 3201 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3202 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3203 | } 3204 | 3205 | const QString sceneSubject = importer->getSceneSubject(); 3206 | if ( !sceneSubject.isEmpty() ) 3207 | { 3208 | lbl = new QLabel( tr( "Subject:" ) ); 3209 | lbl->setObjectName( name % "SceneSubjectLbl" ); 3210 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3211 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3212 | leftLabels.push_back( lbl ); 3213 | 3214 | lbl = new QLabel( sceneSubject ); 3215 | lbl->setObjectName( name % "SceneSubjectValueLbl" ); 3216 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3217 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3218 | } 3219 | 3220 | const QString sceneKeywords = importer->getSceneKeywords(); 3221 | if ( !sceneKeywords.isEmpty() ) 3222 | { 3223 | lbl = new QLabel( tr( "Keywords:" ) ); 3224 | lbl->setObjectName( name % "SceneKeywordsLbl" ); 3225 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3226 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3227 | leftLabels.push_back( lbl ); 3228 | 3229 | lbl = new QLabel( sceneKeywords ); 3230 | lbl->setObjectName( name % "SceneKeywordsValueLbl" ); 3231 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3232 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3233 | } 3234 | 3235 | const QString sceneRevision = importer->getSceneRevision(); 3236 | if ( !sceneRevision.isEmpty() ) 3237 | { 3238 | lbl = new QLabel( tr( "Revision:" ) ); 3239 | lbl->setObjectName( name % "SceneRevisionLbl" ); 3240 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3241 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3242 | leftLabels.push_back( lbl ); 3243 | 3244 | lbl = new QLabel( sceneRevision ); 3245 | lbl->setObjectName( name % "SceneRevisionValueLbl" ); 3246 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3247 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3248 | } 3249 | 3250 | const QString sceneComment = importer->getSceneComment(); 3251 | if ( !sceneComment.isEmpty() ) 3252 | { 3253 | lbl = new QLabel( tr( "Comment:" ) ); 3254 | lbl->setObjectName( name % "SceneCommentLbl" ); 3255 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3256 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3257 | leftLabels.push_back( lbl ); 3258 | 3259 | lbl = new QLabel( sceneComment ); 3260 | lbl->setObjectName( name % "SceneCommentValueLbl" ); 3261 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3262 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3263 | } 3264 | 3265 | const QString vendor = importer->getOriginalAppVendor(); 3266 | if ( !vendor.simplified().isEmpty() ) 3267 | { 3268 | lbl = new QLabel( tr( "Vendor:" ) ); 3269 | lbl->setObjectName( name % "VendorLbl" ); 3270 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3271 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3272 | leftLabels.push_back( lbl ); 3273 | 3274 | lbl = new QLabel( vendor ); 3275 | lbl->setObjectName( name % "VendorValueLbl" ); 3276 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3277 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3278 | } 3279 | 3280 | const QString application = QString( "%1 %2" ) 3281 | .arg( importer->getOriginalAppName() ) 3282 | .arg( importer->getOriginalAppVersion() ); 3283 | if ( !application.simplified().isEmpty() ) 3284 | { 3285 | lbl = new QLabel( tr( "Application:" ) ); 3286 | lbl->setObjectName( name % "ApplicationLbl" ); 3287 | lbl->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 3288 | sceneInfoLyt->addWidget( lbl, row, 0 ); 3289 | leftLabels.push_back( lbl ); 3290 | 3291 | lbl = new QLabel( application ); 3292 | lbl->setObjectName( name % "ApplicationValueLbl" ); 3293 | lbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3294 | sceneInfoLyt->addWidget( lbl, row++, 1 ); 3295 | } 3296 | 3297 | #if DZ_SDK_4_12_OR_GREATER 3298 | if ( DzCollapsibleGroupBox* sceneInfoCGBox = qobject_cast( sceneInfoGBox ) ) 3299 | { 3300 | sceneInfoCGBox->addLayout( sceneInfoLyt ); 3301 | } 3302 | else 3303 | { 3304 | sceneInfoGBox->setLayout( sceneInfoLyt ); 3305 | } 3306 | #else 3307 | sceneInfoGBox->setLayout( sceneInfoLyt ); 3308 | #endif //DZ_SDK_4_12_OR_GREATER 3309 | 3310 | mainLyt->addWidget( sceneInfoGBox ); 3311 | 3312 | QWidget* scrollableOptionsWgt = new QWidget(); 3313 | scrollableOptionsWgt->setObjectName( name % "ScrollableOptionsWgt" ); 3314 | 3315 | 3316 | QVBoxLayout* scrollableOptionsLyt = new QVBoxLayout(); 3317 | scrollableOptionsLyt->setSpacing( margin ); 3318 | scrollableOptionsLyt->setMargin( 0 ); 3319 | 3320 | 3321 | // Properties 3322 | QGroupBox* propertiesGBox = new QGroupBox( tr( "Properties :" ) ); 3323 | propertiesGBox->setObjectName( name % "PropertiesGBox" ); 3324 | 3325 | QVBoxLayout* propertiesLyt = new QVBoxLayout(); 3326 | propertiesLyt->setSpacing( margin ); 3327 | propertiesLyt->setMargin( margin ); 3328 | 3329 | m_data->m_includeRotationLimitsCbx = new QCheckBox(); 3330 | m_data->m_includeRotationLimitsCbx->setObjectName( name % "IncludeRotationLimitsCbx" ); 3331 | m_data->m_includeRotationLimitsCbx->setText( tr( "Include Rotation Limits" ) ); 3332 | propertiesLyt->addWidget( m_data->m_includeRotationLimitsCbx ); 3333 | DzConnect( m_data->m_includeRotationLimitsCbx, SIGNAL(toggled(bool)), 3334 | importer, SLOT(setRotationLimits(bool)) ); 3335 | 3336 | m_data->m_includeAnimationCbx = new QCheckBox(); 3337 | m_data->m_includeAnimationCbx->setObjectName( name % "IncludeAnimationCbx" ); 3338 | m_data->m_includeAnimationCbx->setText( tr( "Include Animation" ) ); 3339 | propertiesLyt->addWidget( m_data->m_includeAnimationCbx ); 3340 | DzConnect( m_data->m_includeAnimationCbx, SIGNAL(toggled(bool)), 3341 | importer, SLOT(setIncludeAnimations(bool)) ); 3342 | 3343 | m_data->m_animationTakeCmb = new QComboBox(); 3344 | m_data->m_animationTakeCmb->setObjectName( name % "TakeToImportCmb" ); 3345 | m_data->m_animationTakeCmb->addItem( tr( c_none ) ); 3346 | //m_data->m_animationTakeCmb->insertSeparator( m_data->m_animationTakeCmb->count() ); 3347 | m_data->m_animationTakeCmb->addItems( importer->getAnimStackNames() ); 3348 | m_data->m_animationTakeCmb->setCurrentIndex( 0 ); 3349 | m_data->m_animationTakeCmb->setFixedHeight( btnHeight ); 3350 | m_data->m_animationTakeCmb->setEnabled( false ); 3351 | propertiesLyt->addWidget( m_data->m_animationTakeCmb ); 3352 | DzConnect( m_data->m_animationTakeCmb, SIGNAL(activated(const QString&)), 3353 | importer, SLOT(setTakeName(const QString&)) ); 3354 | 3355 | DzConnect( m_data->m_includeAnimationCbx, SIGNAL(toggled(bool)), 3356 | m_data->m_animationTakeCmb, SLOT(setEnabled(bool)) ); 3357 | 3358 | propertiesGBox->setLayout( propertiesLyt ); 3359 | 3360 | scrollableOptionsLyt->addWidget( propertiesGBox ); 3361 | 3362 | 3363 | // Geometry 3364 | QGroupBox* geometryGBox = new QGroupBox( tr( "Geometry :" ) ); 3365 | geometryGBox->setObjectName( name % "GeometryGBox" ); 3366 | 3367 | QBoxLayout* geometryLyt = new QVBoxLayout(); 3368 | geometryLyt->setSpacing( margin ); 3369 | geometryLyt->setMargin( margin ); 3370 | 3371 | m_data->m_includePolygonSetsCbx = new QCheckBox(); 3372 | m_data->m_includePolygonSetsCbx->setObjectName( name % "IncludePolygonSetsCbx" ); 3373 | m_data->m_includePolygonSetsCbx->setText( tr( "Include Polygon Sets" ) ); 3374 | geometryLyt->addWidget( m_data->m_includePolygonSetsCbx ); 3375 | DzConnect( m_data->m_includePolygonSetsCbx, SIGNAL(toggled(bool)), 3376 | importer, SLOT(setIncludePolygonSets(bool)) ); 3377 | 3378 | m_data->m_includePolygonGroupsCbx = new QCheckBox(); 3379 | m_data->m_includePolygonGroupsCbx->setObjectName( name % "IncludePolygonGroupsCbx" ); 3380 | m_data->m_includePolygonGroupsCbx->setText( tr( "Include Polygon Groups" ) ); 3381 | geometryLyt->addWidget( m_data->m_includePolygonGroupsCbx ); 3382 | DzConnect( m_data->m_includePolygonGroupsCbx, SIGNAL(toggled(bool)), 3383 | importer, SLOT(setIncludePolygonGroups(bool)) ); 3384 | 3385 | geometryGBox->setLayout( geometryLyt ); 3386 | 3387 | scrollableOptionsLyt->addWidget( geometryGBox ); 3388 | 3389 | 3390 | // Custom Data 3391 | QGroupBox* customDataGBox = new QGroupBox( tr( "Custom Data :" ) ); 3392 | customDataGBox->setObjectName( name % "CustomDataGBox" ); 3393 | 3394 | QVBoxLayout* customDataLyt = new QVBoxLayout(); 3395 | customDataLyt->setSpacing( margin ); 3396 | customDataLyt->setMargin( margin ); 3397 | 3398 | m_data->m_studioNodeNameLabelCbx = new QCheckBox(); 3399 | m_data->m_studioNodeNameLabelCbx->setObjectName( name % "IncludeNodeNameLabelCbx" ); 3400 | m_data->m_studioNodeNameLabelCbx->setText( tr( "Include Node Names/Labels" ) ); 3401 | customDataLyt->addWidget( m_data->m_studioNodeNameLabelCbx ); 3402 | DzConnect( m_data->m_studioNodeNameLabelCbx, SIGNAL(toggled(bool)), 3403 | importer, SLOT(setStudioNodeNamesLabels(bool)) ); 3404 | 3405 | m_data->m_studioPresentationCbx = new QCheckBox(); 3406 | m_data->m_studioPresentationCbx->setObjectName( name % "IncludePresentationCbx" ); 3407 | m_data->m_studioPresentationCbx->setText( tr( "Include Presentation" ) ); 3408 | customDataLyt->addWidget( m_data->m_studioPresentationCbx ); 3409 | DzConnect( m_data->m_studioPresentationCbx, SIGNAL(toggled(bool)), 3410 | importer, SLOT(setStudioNodePresentation(bool)) ); 3411 | 3412 | m_data->m_studioSelectionMapCbx = new QCheckBox(); 3413 | m_data->m_studioSelectionMapCbx->setObjectName( name % "IncludeSelectionMapCbx" ); 3414 | m_data->m_studioSelectionMapCbx->setText( tr( "Include Node Selection Map" ) ); 3415 | customDataLyt->addWidget( m_data->m_studioSelectionMapCbx ); 3416 | DzConnect( m_data->m_studioSelectionMapCbx, SIGNAL(toggled(bool)), 3417 | importer, SLOT(setStudioNodeSelectionMap(bool)) ); 3418 | 3419 | m_data->m_studioSceneIDsCbx = new QCheckBox(); 3420 | m_data->m_studioSceneIDsCbx->setObjectName( name % "IncludeSceneIDssCbx" ); 3421 | m_data->m_studioSceneIDsCbx->setText( tr( "Include Scene IDs" ) ); 3422 | customDataLyt->addWidget( m_data->m_studioSceneIDsCbx ); 3423 | DzConnect( m_data->m_studioSceneIDsCbx, SIGNAL(toggled(bool)), 3424 | importer, SLOT(setStudioSceneIDs(bool)) ); 3425 | 3426 | customDataGBox->setLayout( customDataLyt ); 3427 | 3428 | scrollableOptionsLyt->addWidget( customDataGBox ); 3429 | 3430 | scrollableOptionsWgt->setLayout( scrollableOptionsLyt ); 3431 | 3432 | QScrollArea* scrollableOptionsArea = createScrollableWidget( scrollableOptionsWgt, margin, margin, name % "Options" ); 3433 | 3434 | 3435 | // Footer 3436 | const QString errorList = importer->getErrorList().join( "\n" ); 3437 | 3438 | QGroupBox* reportGrp = new QGroupBox(); 3439 | reportGrp->setObjectName( name % "PreImportReportGBox" ); 3440 | reportGrp->setTitle( tr( "Pre-Import Report :" ) ); 3441 | 3442 | QVBoxLayout* reportLyt = new QVBoxLayout(); 3443 | reportLyt->setSpacing( margin ); 3444 | reportLyt->setMargin( margin ); 3445 | 3446 | QLabel* preImportLbl = new QLabel(); 3447 | preImportLbl->setObjectName( name % "PreImportReportLbl" ); 3448 | preImportLbl->setText( !errorList.isEmpty() ? errorList : tr( "Import Ready." ) ); 3449 | preImportLbl->setTextInteractionFlags( Qt::TextBrowserInteraction ); 3450 | 3451 | QScrollArea* preImportScroll = createScrollableWidget( preImportLbl, margin, margin, name % "PreImportReport" ); 3452 | 3453 | reportLyt->addWidget( preImportScroll, 1 ); 3454 | 3455 | reportGrp->setLayout( reportLyt ); 3456 | 3457 | 3458 | DzDynamicDividerWgt* optionsStagingDvdr = new DzDynamicDividerWgt(); 3459 | optionsStagingDvdr->setObjectName( name % "OptionsReportDvdr" ); 3460 | optionsStagingDvdr->setDividerBar( Qt::Horizontal, DzDividerBar::BSThin ); 3461 | optionsStagingDvdr->setMargin( margin ); 3462 | optionsStagingDvdr->setFirstWidget( scrollableOptionsArea ); 3463 | optionsStagingDvdr->setSecondWidget( reportGrp ); 3464 | optionsStagingDvdr->setPreferredDividerPercent( 0.7 ); 3465 | mainLyt->addWidget( optionsStagingDvdr, 10 ); 3466 | 3467 | setLayout( mainLyt ); 3468 | 3469 | // -------- 3470 | 3471 | int leftWidth = 0; 3472 | for ( int i = 0, n = leftLabels.count(); i < n; ++i ) 3473 | { 3474 | lbl = leftLabels.at( i ); 3475 | const int minWidth = lbl->minimumSizeHint().width(); 3476 | if ( minWidth > leftWidth ) 3477 | { 3478 | leftWidth = minWidth; 3479 | } 3480 | } 3481 | 3482 | for ( int i = 0, n = leftLabels.count(); i < n; ++i ) 3483 | { 3484 | lbl = leftLabels.at( i ); 3485 | lbl->setFixedWidth( leftWidth ); 3486 | } 3487 | 3488 | DzFbxImportFrame::resetOptions(); 3489 | } 3490 | 3491 | /** 3492 | **/ 3493 | DzFbxImportFrame::~DzFbxImportFrame() 3494 | {} 3495 | 3496 | /** 3497 | **/ 3498 | void DzFbxImportFrame::setOptions( const DzFileIOSettings* settings, const QString &filename ) 3499 | { 3500 | assert( settings ); 3501 | if ( !settings ) 3502 | { 3503 | return; 3504 | } 3505 | 3506 | // Properties 3507 | m_data->m_includeRotationLimitsCbx->setChecked( settings->getBoolValue( c_optIncRotationLimits, c_defaultIncludeRotationLimits ) ); 3508 | m_data->m_includeAnimationCbx->setChecked( settings->getBoolValue( c_optIncAnimations, c_defaultIncludeAnimations ) ); 3509 | const QString take = settings->getStringValue( c_optTake, QString() ); 3510 | for ( int i = 0; i < m_data->m_animationTakeCmb->count(); i++ ) 3511 | { 3512 | if ( m_data->m_animationTakeCmb->itemText( i ) == take ) 3513 | { 3514 | m_data->m_animationTakeCmb->setCurrentIndex( i ); 3515 | break; 3516 | } 3517 | } 3518 | 3519 | // Geometry 3520 | m_data->m_includePolygonSetsCbx->setChecked( settings->getBoolValue( c_optIncPolygonSets, c_defaultIncludePolygonSets ) ); 3521 | m_data->m_includePolygonGroupsCbx->setChecked( settings->getBoolValue( c_optIncPolygonGroups, c_defaultIncludePolygonGroups ) ); 3522 | 3523 | // Custom Data 3524 | m_data->m_studioNodeNameLabelCbx->setChecked( settings->getBoolValue( c_optStudioNodeNamesLabels, c_defaultStudioNodeNames ) ); 3525 | m_data->m_studioPresentationCbx->setChecked( settings->getBoolValue( c_optStudioPresentation, c_defaultStudioNodePresentation ) ); 3526 | m_data->m_studioSelectionMapCbx->setChecked( settings->getBoolValue( c_optStudioNodeSelectionMap, c_defaultStudioNodeSelectionMap ) ); 3527 | m_data->m_studioSceneIDsCbx->setChecked( settings->getBoolValue( c_optStudioSceneIDs, c_defaultStudioSceneIDs ) ); 3528 | } 3529 | 3530 | /** 3531 | **/ 3532 | void DzFbxImportFrame::getOptions( DzFileIOSettings* settings ) const 3533 | { 3534 | assert( settings ); 3535 | if ( !settings ) 3536 | { 3537 | return; 3538 | } 3539 | 3540 | // Properties 3541 | settings->setBoolValue( c_optIncRotationLimits, m_data->m_includeRotationLimitsCbx->isChecked() ); 3542 | settings->setBoolValue( c_optIncAnimations, m_data->m_includeAnimationCbx->isChecked() ); 3543 | const QString animTake = m_data->m_animationTakeCmb->currentText(); 3544 | settings->setStringValue( c_optTake, animTake != tr( c_none ) ? animTake : QString() ); 3545 | 3546 | // Geometry 3547 | settings->setBoolValue( c_optIncPolygonSets, m_data->m_includePolygonSetsCbx->isChecked() ); 3548 | settings->setBoolValue( c_optIncPolygonGroups, m_data->m_includePolygonGroupsCbx->isChecked() ); 3549 | 3550 | // Custom Data 3551 | settings->setBoolValue( c_optStudioNodeNamesLabels, m_data->m_studioNodeNameLabelCbx->isChecked() ); 3552 | settings->setBoolValue( c_optStudioPresentation, m_data->m_studioPresentationCbx->isChecked() ); 3553 | settings->setBoolValue( c_optStudioNodeSelectionMap, m_data->m_studioSelectionMapCbx->isChecked() ); 3554 | settings->setBoolValue( c_optStudioSceneIDs, m_data->m_studioSceneIDsCbx->isChecked() ); 3555 | } 3556 | 3557 | /** 3558 | **/ 3559 | void DzFbxImportFrame::applyChanges() 3560 | { 3561 | } 3562 | 3563 | /** 3564 | **/ 3565 | void DzFbxImportFrame::resetOptions() 3566 | { 3567 | DzFileIOSettings* ioSettings = new DzFileIOSettings(); 3568 | m_data->m_importer->getDefaultOptions( ioSettings ); 3569 | setOptions( ioSettings, QString() ); 3570 | } 3571 | 3572 | #include "moc_dzfbximporter.cpp" --------------------------------------------------------------------------------