Browse Source

Merge branch 'master' of https://github.com/assimp/assimp

Kim Kulling 8 years ago
parent
commit
d27e667f1e
62 changed files with 2566 additions and 1651 deletions
  1. 21 13
      .travis.yml
  2. 9 0
      CMakeLists.txt
  3. 5 3
      Readme.md
  4. 1 1
      code/3DSLoader.cpp
  5. 15 4
      code/AssbinExporter.cpp
  6. 3 0
      code/CMakeLists.txt
  7. 5 5
      code/ColladaExporter.cpp
  8. 9 9
      code/ColladaLoader.cpp
  9. 2 2
      code/DefaultLogger.cpp
  10. 9 16
      code/FBXAnimation.cpp
  11. 1 1
      code/FBXCompileConfig.h
  12. 5 12
      code/FBXConverter.cpp
  13. 18 42
      code/FBXDocument.cpp
  14. 6 27
      code/FBXDocument.h
  15. 0 3
      code/FBXModel.cpp
  16. 6 9
      code/FBXNodeAttribute.cpp
  17. 5 11
      code/FBXParser.cpp
  18. 0 19
      code/FBXParser.h
  19. 1 1
      code/IFCProfile.cpp
  20. 2 2
      code/Importer.cpp
  21. 2 0
      code/ImporterRegistry.cpp
  22. 3 3
      code/MMDImporter.cpp
  23. 0 74
      code/MMDPmdParser.h
  24. 0 3
      code/MMDPmxParser.cpp
  25. 0 120
      code/MMDPmxParser.h
  26. 0 32
      code/MMDVmdParser.h
  27. 1 1
      code/OFFLoader.cpp
  28. 1 1
      code/ObjFileMtlImporter.cpp
  29. 2 2
      code/PlyParser.cpp
  30. 8 2
      code/PretransformVertices.cpp
  31. 2 2
      code/SIBImporter.cpp
  32. 1 1
      code/X3DImporter.cpp
  33. 115 217
      code/glTF2Asset.h
  34. 199 523
      code/glTF2Asset.inl
  35. 1 3
      code/glTF2AssetWriter.h
  36. 166 204
      code/glTF2AssetWriter.inl
  37. 200 231
      code/glTF2Exporter.cpp
  38. 16 3
      code/glTF2Exporter.h
  39. 654 0
      code/glTF2Importer.cpp
  40. 91 0
      code/glTF2Importer.h
  41. 2 2
      code/glTFAsset.h
  42. 23 14
      code/glTFAsset.inl
  43. 2 7
      code/glTFAssetWriter.inl
  44. 5 5
      code/glTFExporter.cpp
  45. 13 18
      code/glTFImporter.cpp
  46. 5 0
      contrib/irrXML/CMakeLists.txt
  47. 3 2
      test/CMakeLists.txt
  48. BIN
      test/models/glTF2/BoxTextured-glTF-Binary/BoxTextured.glb
  49. 141 0
      test/models/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf
  50. 197 0
      test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf
  51. BIN
      test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured0.bin
  52. BIN
      test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/CesiumLogoFlat.png
  53. 282 0
      test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured.gltf
  54. BIN
      test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.bin
  55. 17 0
      test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.vert
  56. 29 0
      test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured1.frag
  57. BIN
      test/models/glTF2/BoxTextured-glTF-techniqueWebGL/CesiumLogoFlat.png
  58. 181 0
      test/models/glTF2/BoxTextured-glTF/BoxTextured.gltf
  59. BIN
      test/models/glTF2/BoxTextured-glTF/BoxTextured0.bin
  60. BIN
      test/models/glTF2/BoxTextured-glTF/CesiumLogoFlat.png
  61. 80 0
      test/unit/utglTF2ImportExport.cpp
  62. 1 1
      test/unit/utglTFImportExport.cpp

+ 21 - 13
.travis.yml

@@ -1,6 +1,8 @@
 sudo: required
 language: cpp
 
+cache: ccache
+
 before_install:
   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
   - 'if [ "$TRAVIS_OS_NAME" = "osx" ];  then
@@ -20,24 +22,33 @@ branches:
   only:
     - master
 
-osx_image: xcode8.3
+os:
+  - linux
 
 env:
   global:
   # COVERITY_SCAN_TOKEN
     - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
     - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
-  matrix:
-    - os: linux LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON
+
+matrix:
+  exclude:
+    - os: linux
+      env:
+
+  include:
+    - os: linux
       compiler: gcc
-    - os: linux LINUX=1 TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
-      compiler: clang
-    - os: linux LINUX=1 SHARED_BUILD=ON TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
+      env: LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON
+    - os: linux
       compiler: gcc
-    - os: linux LINUX=1 SHARED_BUILD=ON TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
-      compiler: clang
-    - os: osx
-      osx_image: xcode8.2
+      env: LINUX=1 TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
+    - os: linux
+      compiler: gcc
+      env: LINUX=1 SHARED_BUILD=ON TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
+    - os: linux
+      compiler: gcc
+      env: LINUX=1 SHARED_BUILD=ON TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
 
 install:
   - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
@@ -50,9 +61,6 @@ script:
   - export COVERALLS_SERVICE_NAME=travis-ci
   - export COVERALLS_REPO_TOKEN=abc12345
   - . ./.travis.sh
-os:
-  - linux
-  - osx
  
 after_success:
   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi

+ 9 - 0
CMakeLists.txt

@@ -78,6 +78,10 @@ OPTION ( ASSIMP_COVERALLS
   "Enable this to measure test coverage."
   OFF
 )
+OPTION ( ASSIMP_WERRRO
+  "Treat warnings as errors."
+  OFF
+)
 OPTION ( SYSTEM_IRRXML
   "Use system installed Irrlicht/IrrXML library."
   OFF
@@ -212,6 +216,11 @@ if (ASSIMP_COVERALLS)
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
 endif()
 
+if (ASSIMP_WERROR)
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
+endif()
+
 INCLUDE (FindPkgMacros)
 INCLUDE (PrecompiledHeader)
 

+ 5 - 3
Readme.md

@@ -52,7 +52,8 @@ __Importers__:
 - DXF
 - ENFF
 - FBX
-- GLB/GLTF
+- glTF 1.0 + GLB
+- glTF 2.0
 - HMB
 - IFC-STEP
 - IRR / IRRMESH
@@ -106,8 +107,8 @@ __Exporters__:
 - JSON (for WebGl, via https://github.com/acgessler/assimp2json)
 - ASSBIN
 - STEP
-- glTF (partial)
-- glTF2.0
+- glTF 1.0 (partial)
+- glTF 2.0 (partial)
 
 ### Building ###
 Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
@@ -119,6 +120,7 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
 * [Unity 3d Plugin] (https://www.assetstore.unity3d.com/en/#!/content/91777)
+* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, ~collada)
 
 ### Other tools ###
 [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.

+ 1 - 1
code/3DSLoader.cpp

@@ -1381,7 +1381,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
         bGamma = true;
 
     case Discreet3DS::CHUNK_RGBF:
-        if (sizeof(ai_real) * 3 > diff)   {
+        if (sizeof(float) * 3 > diff)   {
             *out = clrError;
             return;
         }

+ 15 - 4
code/AssbinExporter.cpp

@@ -139,6 +139,17 @@ inline size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v)
     return t;
 }
 
+// -----------------------------------------------------------------------------------
+// Serialize a color value
+template <>
+inline size_t Write<aiColor3D>(IOStream * stream, const aiColor3D& v)
+{
+    size_t t = Write<float>(stream,v.r);
+    t += Write<float>(stream,v.g);
+    t += Write<float>(stream,v.b);
+    return t;
+}
+
 // -----------------------------------------------------------------------------------
 // Serialize a color value
 template <>
@@ -325,7 +336,7 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
         {
             AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
 
-			size_t nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
+			unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
 
             Write<aiString>(&chunk,node->mName);
             Write<aiMatrix4x4>(&chunk,node->mTransformation);
@@ -639,9 +650,9 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
                 Write<float>(&chunk,l->mAttenuationQuadratic);
             }
 
-            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorDiffuse);
-            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorSpecular);
-            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorAmbient);
+            Write<aiColor3D>(&chunk,l->mColorDiffuse);
+            Write<aiColor3D>(&chunk,l->mColorSpecular);
+            Write<aiColor3D>(&chunk,l->mColorAmbient);
 
             if (l->mType == aiLightSource_SPOT) {
                 Write<float>(&chunk,l->mAngleInnerCone);

+ 3 - 0
code/CMakeLists.txt

@@ -61,6 +61,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/color4.inl
   ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
   ${HEADER_PATH}/defs.h
+  ${HEADER_PATH}/Defines.h
   ${HEADER_PATH}/cfileio.h
   ${HEADER_PATH}/light.h
   ${HEADER_PATH}/material.h
@@ -665,6 +666,8 @@ ADD_ASSIMP_IMPORTER( GLTF
   glTF2Asset.inl
   glTF2AssetWriter.h
   glTF2AssetWriter.inl
+  glTF2Importer.cpp
+  glTF2Importer.h
   glTF2Exporter.h
   glTF2Exporter.cpp
 )

+ 5 - 5
code/ColladaExporter.cpp

@@ -866,8 +866,8 @@ void ColladaExporter::WriteController( size_t pIndex)
 
     std::vector<ai_real> bind_poses;
     bind_poses.reserve(mesh->mNumBones * 16);
-    for( size_t i = 0; i < mesh->mNumBones; ++i)
-        for( size_t j = 0; j < 4; ++j)
+    for(unsigned int i = 0; i < mesh->mNumBones; ++i)
+        for( unsigned int j = 0; j < 4; ++j)
             bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4);
 
     WriteFloatArray( idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real*) bind_poses.data(), bind_poses.size() / 16);
@@ -924,11 +924,11 @@ void ColladaExporter::WriteController( size_t pIndex)
 
     ai_uint weight_index = 0;
     std::vector<ai_int> joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1);
-    for( size_t i = 0; i < mesh->mNumBones; ++i)
-        for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
+    for( unsigned int i = 0; i < mesh->mNumBones; ++i)
+        for( unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
         {
             unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId;
-            for( size_t k = 0; k < num_influences[vId]; ++k)
+            for( ai_uint k = 0; k < num_influences[vId]; ++k)
             {
                 if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1)
                 {

+ 9 - 9
code/ColladaLoader.cpp

@@ -119,7 +119,7 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
          *  might be NULL and it's our duty to return true here.
          */
         if (!pIOHandler)return true;
-        const char* tokens[] = {"collada"};
+        const char* tokens[] = {"<collada"};
         return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
     }
     return false;
@@ -728,7 +728,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
                                 ? aiMorphingMethod_MORPH_RELATIVE
                                 : aiMorphingMethod_MORPH_NORMALIZED;
         dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()];
-        dstMesh->mNumAnimMeshes = animMeshes.size();
+        dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
         for (unsigned int i = 0; i < animMeshes.size(); i++)
             dstMesh->mAnimMeshes[i] = animMeshes.at(i);
     }
@@ -1377,9 +1377,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
         {
               aiNodeAnim* dstAnim = new aiNodeAnim;
               dstAnim->mNodeName = nodeName;
-              dstAnim->mNumPositionKeys = resultTrafos.size();
-              dstAnim->mNumRotationKeys= resultTrafos.size();
-              dstAnim->mNumScalingKeys = resultTrafos.size();
+              dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
+              dstAnim->mNumRotationKeys = static_cast<unsigned int>(resultTrafos.size());
+              dstAnim->mNumScalingKeys = static_cast<unsigned int>(resultTrafos.size());
               dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
               dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
               dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
@@ -1445,11 +1445,11 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
                     ++morphAnimChannelIndex;
                 }
 
-                morphAnim->mNumKeys = morphTimeValues.size();
+                morphAnim->mNumKeys = static_cast<unsigned int>(morphTimeValues.size());
                 morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys];
                 for (unsigned int key = 0; key < morphAnim->mNumKeys; key++)
                 {
-                    morphAnim->mKeys[key].mNumValuesAndWeights = morphChannels.size();
+                    morphAnim->mKeys[key].mNumValuesAndWeights = static_cast<unsigned int>(morphChannels.size());
                     morphAnim->mKeys[key].mValues = new unsigned int [morphChannels.size()];
                     morphAnim->mKeys[key].mWeights = new double [morphChannels.size()];
 
@@ -1470,13 +1470,13 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
     {
         aiAnimation* anim = new aiAnimation;
         anim->mName.Set( pName);
-        anim->mNumChannels = anims.size();
+        anim->mNumChannels = static_cast<unsigned int>(anims.size());
         if (anim->mNumChannels > 0)
         {
             anim->mChannels = new aiNodeAnim*[anims.size()];
             std::copy( anims.begin(), anims.end(), anim->mChannels);
         }
-        anim->mNumMorphMeshChannels = morphAnims.size();
+        anim->mNumMorphMeshChannels = static_cast<unsigned int>(morphAnims.size());
         if (anim->mNumMorphMeshChannels > 0)
         {
             anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels];

+ 2 - 2
code/DefaultLogger.cpp

@@ -253,8 +253,8 @@ void DefaultLogger::kill()
 //  Debug message
 void DefaultLogger::OnDebug( const char* message )
 {
-    if ( m_Severity == Logger::NORMAL )
-        return;
+	if ( m_Severity == Logger::NORMAL )
+		return;
 
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];

+ 9 - 16
code/FBXAnimation.cpp

@@ -87,17 +87,16 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 AnimationCurve::~AnimationCurve()
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
-AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
-    const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/)
+AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, 
+        const Document& doc, const char* const * target_prop_whitelist /*= NULL*/, 
+        size_t whitelist_size /*= 0*/)
 : Object(id, element, name)
 , target()
 , doc(doc)
@@ -154,18 +153,16 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
     props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
 }
 
-
 // ------------------------------------------------------------------------------------------------
 AnimationCurveNode::~AnimationCurveNode()
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 const AnimationCurveMap& AnimationCurveNode::Curves() const
 {
-    if(curves.empty()) {
+    if ( curves.empty() ) {
         // resolve attached animation curves
         const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
 
@@ -195,7 +192,6 @@ const AnimationCurveMap& AnimationCurveNode::Curves() const
     return curves;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc)
 : Object(id, element, name)
@@ -207,14 +203,12 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::s
     props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
 }
 
-
 // ------------------------------------------------------------------------------------------------
 AnimationLayer::~AnimationLayer()
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
     size_t whitelist_size /*= 0*/) const
@@ -298,14 +292,13 @@ AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::s
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 AnimationStack::~AnimationStack()
 {
-
+    // empty
 }
 
 } //!FBX
 } //!Assimp
 
-#endif
+#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

+ 1 - 1
code/FBXCompileConfig.h

@@ -66,4 +66,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #   endif
 #endif
 
-#endif
+#endif // INCLUDED_AI_FBX_COMPILECONFIG_H

+ 5 - 12
code/FBXConverter.cpp

@@ -55,9 +55,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "StringComparison.h"
 
 #include <assimp/scene.h>
+
 #include <tuple>
 #include <memory>
-
 #include <iterator>
 #include <vector>
 
@@ -931,7 +931,7 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
         const TransformationComp comp = static_cast< TransformationComp >( i );
 
         if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
-            comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
+                comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
             continue;
         }
 
@@ -949,8 +949,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
     return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
 }
 
-void Converter::GenerateTransformationNodeChain( const Model& model,
-    std::vector<aiNode*>& output_nodes )
+void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes )
 {
     const PropertyTable& props = model.Props();
     const Model::RotOrder rot = model.RotationOrder();
@@ -3124,7 +3123,6 @@ void Converter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, c
     }
 }
 
-
 void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
     const aiVector3D& def_value,
     double& maxTime,
@@ -3145,7 +3143,6 @@ void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, con
 
         valOut[ i ].mTime = temp[ i ].mTime;
 
-
         GetRotationMatrix( order, temp[ i ].mValue, m );
         aiQuaternion quat = aiQuaternion( aiMatrix3x3( m ) );
 
@@ -3164,7 +3161,6 @@ void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, con
     }
 }
 
-
 void Converter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey* out_scale,
     aiVectorKey* out_translation,
     const KeyFrameListList& scaling,
@@ -3223,7 +3219,6 @@ void Converter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey
     }
 }
 
-
 aiQuaternion Converter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrder order )
 {
     aiMatrix4x4 m;
@@ -3232,7 +3227,6 @@ aiQuaternion Converter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrde
     return aiQuaternion( aiMatrix3x3( m ) );
 }
 
-
 void Converter::ConvertScaleKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
     int64_t start, int64_t stop,
     double& maxTime,
@@ -3253,7 +3247,6 @@ void Converter::ConvertScaleKeys( aiNodeAnim* na, const std::vector<const Animat
         InterpolateKeys( na->mScalingKeys, keys, inputs, aiVector3D( 1.0f, 1.0f, 1.0f ), maxTime, minTime );
 }
 
-
 void Converter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
     const LayerMap& /*layers*/,
     int64_t start, int64_t stop,
@@ -3272,7 +3265,6 @@ void Converter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector<const
         InterpolateKeys( na->mPositionKeys, keys, inputs, aiVector3D( 0.0f, 0.0f, 0.0f ), maxTime, minTime );
 }
 
-
 void Converter::ConvertRotationKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
     const LayerMap& /*layers*/,
     int64_t start, int64_t stop,
@@ -3294,7 +3286,8 @@ void Converter::ConvertRotationKeys( aiNodeAnim* na, const std::vector<const Ani
 
 void Converter::TransferDataToScene()
 {
-    ai_assert( !out->mMeshes && !out->mNumMeshes );
+    ai_assert( !out->mMeshes );
+    ai_assert( !out->mNumMeshes );
 
     // note: the trailing () ensures initialization with NULL - not
     // many C++ users seem to know this, so pointing it out to avoid

+ 18 - 42
code/FBXDocument.cpp

@@ -70,13 +70,13 @@ LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc)
 , id(id)
 , flags()
 {
-
+    // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 LazyObject::~LazyObject()
 {
-
+    // empty
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -232,16 +232,15 @@ Object::Object(uint64_t id, const Element& element, const std::string& name)
 , name(name)
 , id(id)
 {
-
+    // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 Object::~Object()
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props)
 : props(props)
@@ -361,7 +360,6 @@ void Document::ReadGlobalSettings()
     globals.reset(new FileGlobalSettings(*this, props));
 }
 
-
 // ------------------------------------------------------------------------------------------------
 void Document::ReadObjects()
 {
@@ -387,7 +385,6 @@ void Document::ReadObjects()
         }
 
         const char* err;
-
         const uint64_t id = ParseTokenAsID(*tok[0], err);
         if(err) {
             DOMError(err,el.second);
@@ -469,8 +466,6 @@ void Document::ReadPropertyTemplates()
     }
 }
 
-
-
 // ------------------------------------------------------------------------------------------------
 void Document::ReadConnections()
 {
@@ -482,7 +477,6 @@ void Document::ReadConnections()
     }
 
     uint64_t insertionOrder = 0l;
-
     const Scope& sconns = *econns->Compound();
     const ElementCollection conns = sconns.GetCollection("C");
     for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
@@ -491,7 +485,9 @@ void Document::ReadConnections()
 
         // PP = property-property connection, ignored for now
         // (tokens: "PP", ID1, "Property1", ID2, "Property2")
-        if(type == "PP") continue;
+        if ( type == "PP" ) {
+            continue;
+        }
 
         const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
         const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
@@ -518,11 +514,10 @@ void Document::ReadConnections()
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 const std::vector<const AnimationStack*>& Document::AnimationStacks() const
 {
-    if (!animationStacksResolved.empty() || !animationStacks.size()) {
+    if (!animationStacksResolved.empty() || animationStacks.empty()) {
         return animationStacksResolved;
     }
 
@@ -540,7 +535,6 @@ const std::vector<const AnimationStack*>& Document::AnimationStacks() const
     return animationStacksResolved;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 LazyObject* Document::GetObject(uint64_t id) const
 {
@@ -551,8 +545,7 @@ LazyObject* Document::GetObject(uint64_t id) const
 #define MAX_CLASSNAMES 6
 
 // ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id,
-    const ConnectionMap& conns) const
+std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const
 {
     std::vector<const Connection*> temp;
 
@@ -569,7 +562,6 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id,
     return temp; // NRVO should handle this
 }
 
-
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
     const ConnectionMap& conns,
@@ -578,17 +570,17 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
 
 {
     ai_assert(classnames);
-    ai_assert(count != 0 && count <= MAX_CLASSNAMES);
+    ai_assert( count != 0 );
+    ai_assert( count <= MAX_CLASSNAMES);
 
     size_t lenghts[MAX_CLASSNAMES];
 
     const size_t c = count;
     for (size_t i = 0; i < c; ++i) {
-        lenghts[i] = strlen(classnames[i]);
+        lenghts[ i ] = strlen(classnames[i]);
     }
 
     std::vector<const Connection*> temp;
-
     const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
         conns.equal_range(id);
 
@@ -620,49 +612,40 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
     return temp; // NRVO should handle this
 }
 
-
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
 {
     return GetConnectionsSequenced(source, ConnectionsBySource());
 }
 
-
-
 // ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest,
-    const char* classname) const
+std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest, const char* classname) const
 {
     const char* arr[] = {classname};
     return GetConnectionsBySourceSequenced(dest, arr,1);
 }
 
-
-
 // ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
-    const char* const* classnames, size_t count) const
+std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source, 
+        const char* const* classnames, size_t count) const
 {
     return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
 }
 
-
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
-    const char* classname) const
+        const char* classname) const
 {
     const char* arr[] = {classname};
     return GetConnectionsByDestinationSequenced(dest, arr,1);
 }
 
-
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
 {
     return GetConnectionsSequenced(dest, ConnectionsByDestination());
 }
 
-
 // ------------------------------------------------------------------------------------------------
 std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
     const char* const* classnames, size_t count) const
@@ -671,10 +654,9 @@ std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(ui
     return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Connection::Connection(uint64_t insertionOrder,  uint64_t src, uint64_t dest, const std::string& prop,
-    const Document& doc)
+        const Document& doc)
 
 : insertionOrder(insertionOrder)
 , prop(prop)
@@ -687,14 +669,12 @@ Connection::Connection(uint64_t insertionOrder,  uint64_t src, uint64_t dest, co
     ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Connection::~Connection()
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 LazyObject& Connection::LazySourceObject() const
 {
@@ -703,7 +683,6 @@ LazyObject& Connection::LazySourceObject() const
     return *lazy;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 LazyObject& Connection::LazyDestinationObject() const
 {
@@ -712,7 +691,6 @@ LazyObject& Connection::LazyDestinationObject() const
     return *lazy;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 const Object* Connection::SourceObject() const
 {
@@ -721,7 +699,6 @@ const Object* Connection::SourceObject() const
     return lazy->Get();
 }
 
-
 // ------------------------------------------------------------------------------------------------
 const Object* Connection::DestinationObject() const
 {
@@ -734,4 +711,3 @@ const Object* Connection::DestinationObject() const
 } // !Assimp
 
 #endif
-

+ 6 - 27
code/FBXDocument.h

@@ -338,12 +338,7 @@ public:
 class Model : public Object
 {
 public:
-    Model(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-    virtual ~Model();
-
-public:
-    enum RotOrder
-    {
+    enum RotOrder {
         RotOrder_EulerXYZ = 0,
         RotOrder_EulerXZY,
         RotOrder_EulerYZX,
@@ -357,8 +352,7 @@ public:
     };
 
 
-    enum TransformInheritance
-    {
+    enum TransformInheritance {
         TransformInheritance_RrSs = 0,
         TransformInheritance_RSrs,
         TransformInheritance_Rrs,
@@ -366,7 +360,10 @@ public:
         TransformInheritance_MAX // end-of-enum sentinel
     };
 
-public:
+    Model(uint64_t id, const Element& element, const Document& doc, const std::string& name);
+
+    virtual ~Model();
+
     fbx_simple_property(QuaternionInterpolate, int, 0)
 
     fbx_simple_property(RotationOffset, aiVector3D, aiVector3D())
@@ -443,7 +440,6 @@ public:
     fbx_simple_property(LODBox, bool, false)
     fbx_simple_property(Freeze, bool, false)
 
-public:
     const std::string& Shading() const {
         return shading;
     }
@@ -462,13 +458,11 @@ public:
         return materials;
     }
 
-
     /** Get geometry links */
     const std::vector<const Geometry*>& GetGeometry() const {
         return geometry;
     }
 
-
     /** Get node attachments */
     const std::vector<const NodeAttribute*>& GetAttributes() const {
         return attributes;
@@ -477,7 +471,6 @@ public:
     /** convenience method to check if the node has a Null node marker */
     bool IsNull() const;
 
-
 private:
     void ResolveLinks(const Element& element, const Document& doc);
 
@@ -805,7 +798,6 @@ private:
 
 typedef std::vector<const AnimationCurveNode*> AnimationCurveNodeList;
 
-
 /** Represents a FBX animation layer (i.e. a list of node animations) */
 class AnimationLayer : public Object
 {
@@ -828,10 +820,8 @@ private:
     const Document& doc;
 };
 
-
 typedef std::vector<const AnimationLayer*> AnimationLayerList;
 
-
 /** Represents a FBX animation stack (i.e. a list of animation layers) */
 class AnimationStack : public Object
 {
@@ -839,7 +829,6 @@ public:
     AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
     virtual ~AnimationStack();
 
-public:
     fbx_simple_property(LocalStart, int64_t, 0L)
     fbx_simple_property(LocalStop, int64_t, 0L)
     fbx_simple_property(ReferenceStart, int64_t, 0L)
@@ -879,7 +868,6 @@ private:
 typedef std::vector<float> WeightArray;
 typedef std::vector<unsigned int> WeightIndexArray;
 
-
 /** DOM class for skin deformer clusters (aka subdeformers) */
 class Cluster : public Deformer
 {
@@ -924,8 +912,6 @@ private:
     const Model* node;
 };
 
-
-
 /** DOM class for skin deformers */
 class Skin : public Deformer
 {
@@ -1009,10 +995,8 @@ public:
 typedef std::map<uint64_t, LazyObject*> ObjectMap;
 typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
 
-
 typedef std::multimap<uint64_t, const Connection*> ConnectionMap;
 
-
 /** DOM class for global document settings, a single instance per document can
  *  be accessed via Document.Globals(). */
 class FileGlobalSettings
@@ -1074,9 +1058,6 @@ private:
     const Document& doc;
 };
 
-
-
-
 /** DOM root for a FBX file */
 class Document
 {
@@ -1154,8 +1135,6 @@ private:
         const ConnectionMap&,
         const char* const* classnames,
         size_t count) const;
-
-private:
     void ReadHeader();
     void ReadObjects();
     void ReadPropertyTemplates();

+ 0 - 3
code/FBXModel.cpp

@@ -77,14 +77,12 @@ Model::Model(uint64_t id, const Element& element, const Document& doc, const std
     ResolveLinks(element,doc);
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Model::~Model()
 {
 
 }
 
-
 // ------------------------------------------------------------------------------------------------
 void Model::ResolveLinks(const Element& element, const Document& doc)
 {
@@ -132,7 +130,6 @@ void Model::ResolveLinks(const Element& element, const Document& doc)
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 bool Model::IsNull() const
 {

+ 6 - 9
code/FBXNodeAttribute.cpp

@@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace FBX {
 
-    using namespace Util;
+using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
 NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
@@ -75,7 +75,7 @@ NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document
 // ------------------------------------------------------------------------------------------------
 NodeAttribute::~NodeAttribute()
 {
-
+    // empty
 }
 
 
@@ -101,33 +101,30 @@ CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Docume
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 CameraSwitcher::~CameraSwitcher()
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : NodeAttribute(id,element,doc,name)
 {
-
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Camera::~Camera()
 {
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : NodeAttribute(id,element,doc,name)
 {
-
+    // empty
 }
 
 

+ 5 - 11
code/FBXParser.cpp

@@ -224,41 +224,36 @@ Parser::Parser (const TokenList& tokens, bool is_binary)
     root.reset(new Scope(*this,true));
 }
 
-
 // ------------------------------------------------------------------------------------------------
 Parser::~Parser()
 {
+    // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
 TokenPtr Parser::AdvanceToNextToken()
 {
     last = current;
     if (cursor == tokens.end()) {
         current = NULL;
-    }
-    else {
+    } else {
         current = *cursor++;
     }
     return current;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 TokenPtr Parser::CurrentToken() const
 {
     return current;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 TokenPtr Parser::LastToken() const
 {
     return last;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
 {
@@ -286,7 +281,7 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
     unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
     ai_assert(length > 0);
 
-    const char* out;
+    const char* out = nullptr;
     const uint64_t id = strtoul10_64(t.begin(),&out,&length);
     if (out > t.end()) {
         err_out = "failed to parse ID (text)";
@@ -296,7 +291,6 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
     return id;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 size_t ParseTokenAsDim(const Token& t, const char*& err_out)
 {
@@ -333,7 +327,7 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out)
         return 0;
     }
 
-    const char* out;
+    const char* out = nullptr;
     const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
     if (out > t.end()) {
         err_out = "failed to parse ID";
@@ -446,7 +440,7 @@ int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
     unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
     ai_assert(length > 0);
 
-    const char* out;
+    const char* out = nullptr;
     const int64_t id = strtol10_64(t.begin(), &out, &length);
     if (out > t.end()) {
         err_out = "failed to parse Int64 (text)";

+ 0 - 19
code/FBXParser.h

@@ -85,12 +85,9 @@ typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> Element
 class Element
 {
 public:
-
     Element(const Token& key_token, Parser& parser);
     ~Element();
 
-public:
-
     const Scope* Compound() const {
         return compound.get();
     }
@@ -104,14 +101,11 @@ public:
     }
 
 private:
-
     const Token& key_token;
     TokenList tokens;
     std::unique_ptr<Scope> compound;
 };
 
-
-
 /** FBX data entity that consists of a 'scope', a collection
  *  of not necessarily unique #Element instances.
  *
@@ -125,14 +119,10 @@ private:
  *  @endverbatim  */
 class Scope
 {
-
 public:
-
     Scope(Parser& parser, bool topLevel = false);
     ~Scope();
 
-public:
-
     const Element* operator[] (const std::string& index) const {
         ElementMap::const_iterator it = elements.find(index);
         return it == elements.end() ? NULL : (*it).second;
@@ -158,28 +148,23 @@ public:
     }
 
 private:
-
     ElementMap elements;
 };
 
-
 /** FBX parsing class, takes a list of input tokens and generates a hierarchy
  *  of nested #Scope instances, representing the fbx DOM.*/
 class Parser
 {
 public:
-
     /** Parse given a token list. Does not take ownership of the tokens -
      *  the objects must persist during the entire parser lifetime */
     Parser (const TokenList& tokens,bool is_binary);
     ~Parser();
 
-public:
     const Scope& GetRootScope() const {
         return *root.get();
     }
 
-
     bool IsBinary() const {
         return is_binary;
     }
@@ -233,8 +218,6 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
 void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
 void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el);
 
-
-
 // extract a required element from a scope, abort if the element cannot be found
 const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
 
@@ -243,8 +226,6 @@ const Scope& GetRequiredScope(const Element& el);
 // get token at a particular index
 const Token& GetRequiredToken(const Element& el, unsigned int index);
 
-
-
 // read a 4x4 matrix from an array of 16 floats
 aiMatrix4x4 ReadMatrix(const Element& element);
 

+ 1 - 1
code/IFCProfile.cpp

@@ -128,7 +128,7 @@ void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh&
             meshout.verts.push_back( IfcVector3( std::cos(angle)*radius, std::sin(angle)*radius, 0.f ));
         }
 
-        meshout.vertcnt.push_back(segments);
+        meshout.vertcnt.push_back(static_cast<unsigned int>(segments));
     }
     else if( const IfcIShapeProfileDef* const ishape = def.ToPtr<IfcIShapeProfileDef>()) {
         // construct simplified IBeam shape

+ 2 - 2
code/Importer.cpp

@@ -831,8 +831,8 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
     pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
 
     // update private scene flags
-  if( pimpl->mScene )
-    ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
+    if( pimpl->mScene )
+      ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
 
     // clear any data allocated by post-process steps
     pimpl->mPPShared->Clean();

+ 2 - 0
code/ImporterRegistry.cpp

@@ -182,6 +182,7 @@ corresponding preprocessor flag to selectively disable formats.
 #endif
 #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
 #   include "glTFImporter.h"
+#   include "glTF2Importer.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
 #   include "C4DImporter.h"
@@ -336,6 +337,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
 #endif
 #if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER )
     out.push_back( new glTFImporter() );
+    out.push_back( new glTF2Importer() );
 #endif
 #if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER )
     out.push_back( new C4DImporter() );

+ 3 - 3
code/MMDImporter.cpp

@@ -278,7 +278,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
       bone_vertex_map[vsBDEF2_ptr->bone_index1].push_back(
           aiVertexWeight(index, vsBDEF2_ptr->bone_weight));
       bone_vertex_map[vsBDEF2_ptr->bone_index2].push_back(
-          aiVertexWeight(index, 1.0 - vsBDEF2_ptr->bone_weight));
+          aiVertexWeight(index, 1.0f - vsBDEF2_ptr->bone_weight));
       break;
     case pmx::PmxVertexSkinningType::BDEF4:
       bone_vertex_map[vsBDEF4_ptr->bone_index1].push_back(
@@ -295,7 +295,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
       bone_vertex_map[vsSDEF_ptr->bone_index1].push_back(
           aiVertexWeight(index, vsSDEF_ptr->bone_weight));
       bone_vertex_map[vsSDEF_ptr->bone_index2].push_back(
-          aiVertexWeight(index, 1.0 - vsSDEF_ptr->bone_weight));
+          aiVertexWeight(index, 1.0f - vsSDEF_ptr->bone_weight));
       break;
     case pmx::PmxVertexSkinningType::QDEF:
       const auto vsQDEF_ptr =
@@ -325,7 +325,7 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
     aiMatrix4x4::Translation(-pos, pBone->mOffsetMatrix);
     auto it = bone_vertex_map.find(ii);
     if (it != bone_vertex_map.end()) {
-      pBone->mNumWeights = it->second.size();
+      pBone->mNumWeights = static_cast<unsigned int>(it->second.size());
       pBone->mWeights = it->second.data();
       it->second.swap(*(new vector<aiVertexWeight>));
     }

+ 0 - 74
code/MMDPmdParser.h

@@ -49,17 +49,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace pmd
 {
-	/// ヘッダ
 	class PmdHeader
 	{
 	public:
-		/// モデル名
 		std::string name;
-		/// モデル名(英語)
 		std::string name_english;
-		/// コメント
 		std::string comment;
-		/// コメント(英語)
 		std::string comment_english;
 
 		bool Read(std::ifstream* stream)
@@ -83,26 +78,19 @@ namespace pmd
 		}
 	};
 
-	/// 頂点
 	class PmdVertex
 	{
 	public:
-		/// 位置
 		float position[3];
 
-		/// 法線
 		float normal[3];
 
-		/// UV座標
 		float uv[2];
 
-		/// 関連ボーンインデックス
 		uint16_t bone_index[2];
 
-		/// ボーンウェイト
 		uint8_t bone_weight;
 
-		/// エッジ不可視
 		bool edge_invisible;
 
 		bool Read(std::ifstream* stream)
@@ -117,27 +105,17 @@ namespace pmd
 		}
 	};
 
-	/// 材質
 	class PmdMaterial
 	{
 	public:
-		/// 減衰色
 		float diffuse[4];
-		/// 光沢度
 		float power;
-		/// 光沢色
 		float specular[3];
-		/// 環境色
 		float ambient[3];
-		/// トーンインデックス
 		uint8_t toon_index;
-		/// エッジ
 		uint8_t edge_flag;
-		/// インデックス数
 		uint32_t index_count;
-		/// テクスチャファイル名
 		std::string texture_filename;
-		/// スフィアファイル名
 		std::string sphere_filename;
 
 		bool Read(std::ifstream* stream)
@@ -180,23 +158,15 @@ namespace pmd
 		RotationMovement
 	};
 
-	/// ボーン
 	class PmdBone
 	{
 	public:
-		/// ボーン名
 		std::string name;
-		/// ボーン名(英語)
 		std::string name_english;
-		/// 親ボーン番号
 		uint16_t parent_bone_index;
-		/// 末端ボーン番号
 		uint16_t tail_pos_bone_index;
-		/// ボーン種類
 		BoneType bone_type;
-		/// IKボーン番号
 		uint16_t ik_parent_bone_index;
-		/// ボーンのヘッドの位置
 		float bone_head_pos[3];
 
 		void Read(std::istream *stream)
@@ -219,19 +189,13 @@ namespace pmd
 		}
 	};
 
-	/// IK
 	class PmdIk
 	{
 	public:
-		/// IKボーン番号
 		uint16_t ik_bone_index;
-		/// IKターゲットボーン番号
 		uint16_t target_bone_index;
-		/// 再帰回数
 		uint16_t interations;
-		/// 角度制限
 		float angle_limit;
-		/// 影響下ボーン番号
 		std::vector<uint16_t> ik_child_bone_index;
 
 		void Read(std::istream *stream)
@@ -303,7 +267,6 @@ namespace pmd
 		}
 	};
 
-	/// ボーン枠用の枠名
 	class PmdBoneDispName
 	{
 	public:
@@ -338,59 +301,36 @@ namespace pmd
 		}
 	};
 
-	/// 衝突形状
 	enum class RigidBodyShape : uint8_t
 	{
-		/// 球
 		Sphere = 0,
-		/// 直方体
 		Box = 1,
-		/// カプセル
 		Cpusel = 2
 	};
 
-	/// 剛体タイプ
 	enum class RigidBodyType : uint8_t
 	{
-		/// ボーン追従
 		BoneConnected = 0,
-		/// 物理演算
 		Physics = 1,
-		/// 物理演算(Bone位置合せ)
 		ConnectedPhysics = 2
 	};
 
-	/// 剛体
 	class PmdRigidBody
 	{
 	public:
-		/// 名前
 		std::string name;
-		/// 関連ボーン番号
 		uint16_t related_bone_index;
-		/// グループ番号
 		uint8_t group_index;
-		/// マスク
 		uint16_t mask;
-		/// 形状
 		RigidBodyShape shape;
-		/// 大きさ
 		float size[3];
-		/// 位置
 		float position[3];
-		/// 回転
 		float orientation[3];
-		/// 質量
 		float weight;
-		/// 移動ダンピング
 		float linear_damping;
-		/// 回転ダンピング
 		float anglar_damping;
-		/// 反発係数
 		float restitution;
-		/// 摩擦係数
 		float friction;
-		/// 演算方法
 		RigidBodyType rigid_type;
 
 		void Read(std::istream *stream)
@@ -414,31 +354,19 @@ namespace pmd
 		}
 	};
 
-	/// 剛体の拘束
 	class PmdConstraint
 	{
 	public:
-		/// 名前
 		std::string name;
-		/// 剛体Aのインデックス
 		uint32_t rigid_body_index_a;
-		/// 剛体Bのインデックス
 		uint32_t rigid_body_index_b;
-		/// 位置
 		float position[3];
-		/// 回転
 		float orientation[3];
-		/// 最小移動制限
 		float linear_lower_limit[3];
-		/// 最大移動制限
 		float linear_upper_limit[3];
-		/// 最小回転制限
 		float angular_lower_limit[3];
-		/// 最大回転制限
 		float angular_upper_limit[3];
-		/// 移動に対する復元力
 		float linear_stiffness[3];
-		/// 回転に対する復元力
 		float angular_stiffness[3];
 
 		void Read(std::istream *stream)
@@ -459,7 +387,6 @@ namespace pmd
 		}
 	};
 
-	/// PMDモデル
 	class PmdModel
 	{
 	public:
@@ -491,7 +418,6 @@ namespace pmd
 			return result;
 		}
 
-		/// ファイルからPmdModelを生成する
 		static std::unique_ptr<PmdModel> LoadFromStream(std::ifstream *stream)
 		{
 			auto result = mmd::make_unique<PmdModel>();

+ 0 - 3
code/MMDPmxParser.cpp

@@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace pmx
 {
-	/// インデックス値を読み込む
 	int ReadIndex(std::istream *stream, int size)
 	{
 		switch (size)
@@ -79,7 +78,6 @@ namespace pmx
 		}
 	}
 
-	/// 文字列を読み込む
 	std::string ReadString(std::istream *stream, uint8_t encoding)
 	{
 		int size;
@@ -607,7 +605,6 @@ namespace pmx
 			this->joints[i].Read(stream, &setting);
 		}
 
-		//// ソフトボディ
 		//if (this->version == 2.1f)
 		//{
 		//	stream->read((char*) &this->soft_body_count, sizeof(int));

+ 0 - 120
code/MMDPmxParser.h

@@ -49,7 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace pmx
 {
-	/// インデックス設定
 	class PmxSetting
 	{
 	public:
@@ -64,26 +63,17 @@ namespace pmx
 			, rigidbody_index_size(0)
 		{}
 
-		/// エンコード方式
 		uint8_t encoding;
-		/// 追加UV数
 		uint8_t uv;
-		/// 頂点インデックスサイズ
 		uint8_t vertex_index_size;
-		/// テクスチャインデックスサイズ
 		uint8_t texture_index_size;
-		/// マテリアルインデックスサイズ
 		uint8_t material_index_size;
-		/// ボーンインデックスサイズ
 		uint8_t bone_index_size;
-		/// モーフインデックスサイズ
 		uint8_t morph_index_size;
-		/// 剛体インデックスサイズ
 		uint8_t rigidbody_index_size;
 		void Read(std::istream *stream);
 	};
 
-	/// 頂点スキニングタイプ
 	enum class PmxVertexSkinningType : uint8_t
 	{
 		BDEF1 = 0,
@@ -93,7 +83,6 @@ namespace pmx
 		QDEF = 4,
 	};
 
-	/// 頂点スキニング
 	class PmxVertexSkinning
 	{
 	public:
@@ -200,7 +189,6 @@ namespace pmx
 		void Read(std::istream *stresam, PmxSetting *setting);
 	};
 
-	/// 頂点
 	class PmxVertex
 	{
 	public:
@@ -219,24 +207,16 @@ namespace pmx
 			}
 		}
 
-		/// 位置
 		float position[3];
-		/// 法線
 		float normal[3];
-		/// テクスチャ座標
 		float uv[2];
-		/// 追加テクスチャ座標
 		float uva[4][4];
-		/// スキニングタイプ
 		PmxVertexSkinningType skinning_type;
-		/// スキニング
 		std::unique_ptr<PmxVertexSkinning> skinning;
-		/// エッジ倍率
 		float edge;
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
 
-	/// マテリアル
 	class PmxMaterial
 	{
 	public:
@@ -261,42 +241,25 @@ namespace pmx
 			}
 		}
 
-		/// モデル名
 		std::string material_name;
-		/// モデル英名
 		std::string material_english_name;
-		/// 減衰色
 		float diffuse[4];
-		/// 光沢色
 		float specular[3];
-		/// 光沢度
 		float specularlity;
-		/// 環境色
 		float ambient[3];
-		/// 描画フラグ
 		uint8_t flag;
-		/// エッジ色
 		float edge_color[4];
-		/// エッジサイズ
 		float edge_size;
-		/// アルベドテクスチャインデックス
 		int diffuse_texture_index;
-		/// スフィアテクスチャインデックス
 		int sphere_texture_index;
-		/// スフィアテクスチャ演算モード
 		uint8_t sphere_op_mode;
-		/// 共有トゥーンフラグ
 		uint8_t common_toon_flag;
-		/// トゥーンテクスチャインデックス
 		int toon_texture_index;
-		/// メモ
 		std::string memo;
-		/// 頂点インデックス数
 		int index_count;
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
 
-	/// リンク
 	class PmxIkLink
 	{
 	public:
@@ -310,18 +273,13 @@ namespace pmx
 			}
 		}
 
-		/// リンクボーンインデックス
 		int link_target;
-		/// 角度制限
 		uint8_t angle_lock;
-		/// 最大制限角度
 		float max_radian[3];
-		/// 最小制限角度
 		float min_radian[3];
 		void Read(std::istream *stream, PmxSetting *settingn);
 	};
 
-	/// ボーン
 	class PmxBone
 	{
 	public:
@@ -347,43 +305,24 @@ namespace pmx
 			}
 		}
 
-		/// ボーン名
 		std::string bone_name;
-		/// ボーン英名
 		std::string bone_english_name;
-		/// 位置
 		float position[3];
-		/// 親ボーンインデックス
 		int parent_index;
-		/// 階層
 		int level;
-		/// ボーンフラグ
 		uint16_t bone_flag;
-		/// 座標オフセット(has Target)
 		float offset[3];
-		/// 接続先ボーンインデックス(not has Target)
 		int target_index;
-		/// 付与親ボーンインデックス
 		int grant_parent_index;
-		/// 付与率
 		float grant_weight;
-		/// 固定軸の方向
 		float lock_axis_orientation[3];
-		/// ローカル軸のX軸方向
 		float local_axis_x_orientation[3];
-		/// ローカル軸のY軸方向
 		float local_axis_y_orientation[3];
-		/// 外部親変形のkey値
 		int key;
-		/// IKターゲットボーン
 		int ik_target_bone_index;
-		/// IKループ回数
 		int ik_loop;
-		/// IKループ計算時の角度制限(ラジアン)
 		float ik_loop_angle_limit;
-		/// IKリンク数
 		int ik_link_count;
-		/// IKリンク
 		std::unique_ptr<PmxIkLink []> ik_links;
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
@@ -543,7 +482,6 @@ namespace pmx
 		void Read(std::istream *stream, PmxSetting *setting); //override;
 	};
 
-	/// モーフ
 	class PmxMorph
 	{
 	public:
@@ -551,34 +489,21 @@ namespace pmx
 			: offset_count(0)
 		{
 		}
-		/// モーフ名
 		std::string morph_name;
-		/// モーフ英名
 		std::string morph_english_name;
-		/// カテゴリ
 		MorphCategory category;
-		/// モーフタイプ
 		MorphType morph_type;
-		/// オフセット数
 		int offset_count;
-		/// 頂点モーフ配列
 		std::unique_ptr<PmxMorphVertexOffset []> vertex_offsets;
-		/// UVモーフ配列
 		std::unique_ptr<PmxMorphUVOffset []> uv_offsets;
-		/// ボーンモーフ配列
 		std::unique_ptr<PmxMorphBoneOffset []> bone_offsets;
-		/// マテリアルモーフ配列
 		std::unique_ptr<PmxMorphMaterialOffset []> material_offsets;
-		/// グループモーフ配列
 		std::unique_ptr<PmxMorphGroupOffset []> group_offsets;
-		/// フリップモーフ配列
 		std::unique_ptr<PmxMorphFlipOffset []> flip_offsets;
-		/// インパルスモーフ配列
 		std::unique_ptr<PmxMorphImplusOffset []> implus_offsets;
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
 
-	/// 枠内要素
 	class PmxFrameElement
 	{
 	public:
@@ -587,14 +512,11 @@ namespace pmx
 			, index(0)
 		{
 		}
-		/// 要素対象
 		uint8_t element_target;
-		/// 要素対象インデックス
 		int index;
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
 
-	/// 表示枠
 	class PmxFrame
 	{
 	public:
@@ -603,15 +525,10 @@ namespace pmx
 			, element_count(0)
 		{
 		}
-		/// 枠名
 		std::string frame_name;
-		/// 枠英名
 		std::string frame_english_name;
-		/// 特殊枠フラグ
 		uint8_t frame_flag;
-		/// 枠内要素数
 		int element_count;
-		/// 枠内要素配列
 		std::unique_ptr<PmxFrameElement []> elements;
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
@@ -637,17 +554,11 @@ namespace pmx
 				orientation[i] = 0.0f;
 			}
 		}
-		/// 剛体名
 		std::string girid_body_name;
-		/// 剛体英名
 		std::string girid_body_english_name;
-		/// 関連ボーンインデックス
 		int target_bone;
-		/// グループ
 		uint8_t group;
-		/// マスク
 		uint16_t mask;
-		/// 形状
 		uint8_t shape;
 		float size[3];
 		float position[3];
@@ -818,7 +729,6 @@ namespace pmx
 		void Read(std::istream *stream, PmxSetting *setting);
 	};
 
-	/// PMXモデル
 	class PmxModel
 	{
 	public:
@@ -836,65 +746,35 @@ namespace pmx
 			, soft_body_count(0)
 		{}
 
-		/// バージョン
 		float version;
-		/// 設定
 		PmxSetting setting;
-		/// モデル名
 		std::string model_name;
-		/// モデル英名
 		std::string model_english_name;
-		/// コメント
 		std::string model_comment;
-		/// 英語コメント
 		std::string model_english_comment;
-		/// 頂点数
 		int vertex_count;
-		/// 頂点配列
 		std::unique_ptr<PmxVertex []> vertices;
-		/// インデックス数
 		int index_count;
-		/// インデックス配列
 		std::unique_ptr<int []> indices;
-		/// テクスチャ数
 		int texture_count;
-		/// テクスチャ配列
 		std::unique_ptr< std::string []> textures;
-		/// マテリアル数
 		int material_count;
-		/// マテリアル
 		std::unique_ptr<PmxMaterial []> materials;
-		/// ボーン数
 		int bone_count;
-		/// ボーン配列
 		std::unique_ptr<PmxBone []> bones;
-		/// モーフ数
 		int morph_count;
-		/// モーフ配列
 		std::unique_ptr<PmxMorph []> morphs;
-		/// 表示枠数
 		int frame_count;
-		/// 表示枠配列
 		std::unique_ptr<PmxFrame [] > frames;
-		/// 剛体数
 		int rigid_body_count;
-		/// 剛体配列
 		std::unique_ptr<PmxRigidBody []> rigid_bodies;
-		/// ジョイント数
 		int joint_count;
-		/// ジョイント配列
 		std::unique_ptr<PmxJoint []> joints;
-		/// ソフトボディ数
 		int soft_body_count;
-		/// ソフトボディ配列
 		std::unique_ptr<PmxSoftBody []> soft_bodies;
-		/// モデル初期化
 		void Init();
-		/// モデル読み込み
 		void Read(std::istream *stream);
-		///// ファイルからモデルの読み込み
 		//static std::unique_ptr<PmxModel> ReadFromFile(const char *filename);
-		///// 入力ストリームからモデルの読み込み
 		//static std::unique_ptr<PmxModel> ReadFromStream(std::istream *stream);
 	};
 }

+ 0 - 32
code/MMDVmdParser.h

@@ -50,19 +50,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace vmd
 {
-	/// ボーンフレーム
 	class VmdBoneFrame
 	{
 	public:
-		/// ボーン名
 		std::string name;
-		/// フレーム番号
 		int frame;
-		/// 位置
 		float position[3];
-		/// 回転
 		float orientation[4];
-		/// 補間曲線
 		char interpolation[4][4][4];
 
 		void Read(std::istream* stream)
@@ -86,15 +80,11 @@ namespace vmd
 		}
 	};
 
-	/// 表情フレーム
 	class VmdFaceFrame
 	{
 	public:
-		/// 表情名
 		std::string face_name;
-		/// 表情の重み
 		float weight;
-		/// フレーム番号
 		uint32_t frame;
 
 		void Read(std::istream* stream)
@@ -114,23 +104,15 @@ namespace vmd
 		}
 	};
 
-	/// カメラフレーム
 	class VmdCameraFrame
 	{
 	public:
-		/// フレーム番号
 		int frame;
-		/// 距離
 		float distance;
-		/// 位置
 		float position[3];
-		/// 回転
 		float orientation[3];
-		/// 補間曲線
 		char interpolation[6][4];
-		/// 視野角
 		float angle;
-		/// 不明データ
 		char unknown[3];
 
 		void Read(std::istream *stream)
@@ -156,15 +138,11 @@ namespace vmd
 		}
 	};
 
-	/// ライトフレーム
 	class VmdLightFrame
 	{
 	public:
-		/// フレーム番号
 		int frame;
-		/// 色
 		float color[3];
-		/// 位置
 		float position[3];
 
 		void Read(std::istream* stream)
@@ -182,7 +160,6 @@ namespace vmd
 		}
 	};
 
-	/// IKの有効無効
 	class VmdIkEnable
 	{
 	public:
@@ -190,7 +167,6 @@ namespace vmd
 		bool enable;
 	};
 
-	/// IKフレーム
 	class VmdIkFrame
 	{
 	public:
@@ -229,23 +205,15 @@ namespace vmd
 		}
 	};
 
-	/// VMDモーション
 	class VmdMotion
 	{
 	public:
-		/// モデル名
 		std::string model_name;
-		/// バージョン
 		int version;
-		/// ボーンフレーム
 		std::vector<VmdBoneFrame> bone_frames;
-		/// 表情フレーム
 		std::vector<VmdFaceFrame> face_frames;
-		/// カメラフレーム
 		std::vector<VmdCameraFrame> camera_frames;
-		/// ライトフレーム
 		std::vector<VmdLightFrame> light_frames;
-		/// IKフレーム
 		std::vector<VmdIkFrame> ik_frames;
 
 		static std::unique_ptr<VmdMotion> LoadFromFile(char const *filename)

+ 1 - 1
code/OFFLoader.cpp

@@ -94,7 +94,7 @@ bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
     {
         if (!pIOHandler)return true;
         const char* tokens[] = {"off"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,3);
     }
     return false;
 }

+ 1 - 1
code/ObjFileMtlImporter.cpp

@@ -304,7 +304,7 @@ void ObjFileMtlImporter::createMaterial()
         m_pModel->m_pCurrentMaterial = new ObjFile::Material();
         m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
         if (m_pModel->m_pCurrentMesh) {
-            m_pModel->m_pCurrentMesh->m_uiMaterialIndex = m_pModel->m_MaterialLib.size() - 1;
+            m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
         }
         m_pModel->m_MaterialLib.push_back( name );
         m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;

+ 2 - 2
code/PlyParser.cpp

@@ -618,7 +618,7 @@ bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, DOM* p_pc
   }
 
   streamBuffer.getNextBlock(buffer);
-  unsigned int bufferSize = buffer.size();
+  unsigned int bufferSize = static_cast<unsigned int>(buffer.size());
   const char* pCur = (char*)&buffer[0];
   if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE))
   {
@@ -1025,7 +1025,7 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
       buffer = std::vector<char>(buffer.end() - bufferSize, buffer.end());
       buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end());
       nbuffer.clear();
-      bufferSize = buffer.size();
+      bufferSize = static_cast<unsigned int>(buffer.size());
       pCur = (char*)&buffer[0];
     }
     else

+ 8 - 2
code/PretransformVertices.cpp

@@ -160,6 +160,11 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign
             unsigned int& num_ref = num_refs[pcNode->mMeshes[i]];
             ai_assert(0 != num_ref);
             --num_ref;
+            // Save the name of the last mesh
+            if (num_ref==0)
+            {
+                pcMeshOut->mName = pcMesh->mName;
+            }
 
             if (identity)   {
                 // copy positions without modifying them
@@ -626,9 +631,10 @@ void PretransformVertices::Execute( aiScene* pScene)
 
         // now delete all nodes in the scene and build a new
         // flat node graph with a root node and some level 1 children
+        aiNode* newRoot = new aiNode();
+        newRoot->mName = pScene->mRootNode->mName;
         delete pScene->mRootNode;
         pScene->mRootNode = new aiNode();
-        pScene->mRootNode->mName.Set("<dummy_root>");
 
         if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras)
         {
@@ -646,7 +652,7 @@ void PretransformVertices::Execute( aiScene* pScene)
             {
                 aiNode* pcNode = *nodes = new aiNode();
                 pcNode->mParent = pScene->mRootNode;
-                pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"mesh_%u",i);
+                pcNode->mName = pScene->mMeshes[i]->mName;
 
                 // setup mesh indices
                 pcNode->mNumMeshes = 1;

+ 2 - 2
code/SIBImporter.cpp

@@ -201,7 +201,7 @@ static aiString ReadString(StreamReaderLE* stream, uint32_t numWChars)
     //ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion);
     //*dest = '\0';
 
-    str[str.size()-1] = '\0';
+    str[str.size()] = '\0';
     // Return the final string.
     aiString result = aiString((const char *)&str[0]);
     //delete[] str;
@@ -827,7 +827,7 @@ static void ReadInstance(SIB* sib, StreamReaderLE* stream)
 static void CheckVersion(StreamReaderLE* stream)
 {
     uint32_t version = stream->GetU4();
-    if ( version != 1 ) {
+    if ( version < 1 || version > 2 ) {
         throw DeadlyImportError( "SIB: Unsupported file version." );
     }
 }

+ 1 - 1
code/X3DImporter.cpp

@@ -558,7 +558,7 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector
 
         WordIterator wordItBegin(val, val + strlen(val));
         WordIterator wordItEnd;
-        std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atof(match); });
+        std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return static_cast<float>(atof(match)); });
     }
 }
 

+ 115 - 217
code/glTF2Asset.h

@@ -43,8 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * Declares a glTF class to handle gltf/glb files
  *
  * glTF Extensions Support:
- *   KHR_binary_glTF: full
- *   KHR_materials_common: full
+ *   KHR_materials_pbrSpecularGlossiness full
  */
 #ifndef GLTF2ASSET_H_INC
 #define GLTF2ASSET_H_INC
@@ -130,15 +129,12 @@ namespace glTF2
 
     struct BufferView; // here due to cross-reference
     struct Texture;
-    struct Light;
     struct Skin;
 
-
     // Vec/matrix types, as raw float arrays
     typedef float (vec3)[3];
     typedef float (vec4)[4];
-    typedef float (mat4)[16];
-
+	typedef float (mat4)[16];
 
     namespace Util
     {
@@ -166,23 +162,36 @@ namespace glTF2
 
 
     //! Magic number for GLB files
-    #define AI_GLB_MAGIC_NUMBER "glTF"
+	#define AI_GLB_MAGIC_NUMBER "glTF"
+
+	#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
+	#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
+	#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
+	#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
+	#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
+	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
+	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR "$clr.diffuse", 0, 1
+	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR "$clr.specular", 0, 1
+	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
+	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE aiTextureType_DIFFUSE, 1
+	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE aiTextureType_UNKNOWN, 1
+
+	#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
+	#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
+	#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
+	#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
+	#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
+
+	#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
+	#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
+	#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
+	#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
+	#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
 
     #ifdef ASSIMP_API
         #include "./../include/assimp/Compiler/pushpack1.h"
     #endif
 
-    //! For the KHR_binary_glTF extension (binary .glb file)
-    //! 20-byte header (+ the JSON + a "body" data section)
-    struct GLB_Header
-    {
-        uint8_t magic[4];     //!< Magic number: "glTF"
-        uint32_t version;     //!< Version number
-        uint32_t length;      //!< Total length of the Binary glTF, including header, scene, and body, in bytes
-        uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
-        uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
-    } PACK_STRUCT;
-
     #ifdef ASSIMP_API
         #include "./../include/assimp/Compiler/poppack1.h"
     #endif
@@ -232,7 +241,7 @@ namespace glTF2
             case ComponentType_UNSIGNED_BYTE:
                 return 1;
             default:
-                throw DeadlyImportError("GLTF: Unsupported Component Type "+t);
+                throw DeadlyImportError("GLTF: Unsupported Component Type " + std::to_string(t));
         }
     }
 
@@ -244,15 +253,17 @@ namespace glTF2
     };
 
     //! Values for the Sampler::magFilter field
-    enum SamplerMagFilter
+    enum class SamplerMagFilter: unsigned int
     {
+        UNSET = 0,
         SamplerMagFilter_Nearest = 9728,
         SamplerMagFilter_Linear = 9729
     };
 
     //! Values for the Sampler::minFilter field
-    enum SamplerMinFilter
+    enum class SamplerMinFilter: unsigned int
     {
+        UNSET = 0,
         SamplerMinFilter_Nearest = 9728,
         SamplerMinFilter_Linear = 9729,
         SamplerMinFilter_Nearest_Mipmap_Nearest = 9984,
@@ -262,11 +273,12 @@ namespace glTF2
     };
 
     //! Values for the Sampler::wrapS and Sampler::wrapT field
-    enum SamplerWrap
+    enum class SamplerWrap: unsigned int
     {
-        SamplerWrap_Clamp_To_Edge = 33071,
-        SamplerWrap_Mirrored_Repeat = 33648,
-        SamplerWrap_Repeat = 10497
+        UNSET = 0,
+        Clamp_To_Edge = 33071,
+        Mirrored_Repeat = 33648,
+        Repeat = 10497
     };
 
     //! Values for the Texture::format and Texture::internalFormat fields
@@ -382,6 +394,7 @@ namespace glTF2
     struct Object
     {
         int index;        //!< The index of this object within its property container
+        int oIndex;       //!< The original index of this object defined in the JSON
         std::string id;   //!< The globally unique ID used to reference this object
         std::string name; //!< The user-defined name of this object
 
@@ -629,7 +642,7 @@ namespace glTF2
                 float zfar;  //! The floating-point distance to the far clipping plane. (required)
                 float znear; //! The floating-point distance to the near clipping plane. (required)
             } ortographic;
-        };
+        } cameraProperties;
 
         Camera() {}
         void Read(Value& obj, Asset& r);
@@ -668,43 +681,68 @@ namespace glTF2
         inline uint8_t* StealData();
 
         inline void SetData(uint8_t* data, size_t length, Asset& r);
-    };
+	};
+
+	const vec4 defaultBaseColor = {1, 1, 1, 1};
+	const vec3 defaultEmissiveFactor = {0, 0, 0};
+	const vec4 defaultDiffuseFactor = {1, 1, 1, 1};
+	const vec3 defaultSpecularFactor = {1, 1, 1};
 
-    //! Holds a material property that can be a texture or a color
-    struct TexProperty
+    struct TextureInfo
     {
         Ref<Texture> texture;
-        vec4 color;
+        unsigned int index;
+        unsigned int texCoord = 0;
     };
 
-    //! The material appearance of a primitive.
-    struct Material : public Object
+    struct NormalTextureInfo : TextureInfo
     {
-        //Ref<Sampler> source; //!< The ID of the technique.
-        //std::gltf_unordered_map<std::string, std::string> values; //!< A dictionary object of parameter values.
+        float scale = 1;
+    };
 
-        //! Techniques defined by KHR_materials_common
-        enum Technique
-        {
-            Technique_undefined = 0,
-            Technique_BLINN,
-            Technique_PHONG,
-            Technique_LAMBERT,
-            Technique_CONSTANT
-        };
+    struct OcclusionTextureInfo : TextureInfo
+    {
+        float strength = 1;
+    };
 
-        TexProperty ambient;
-        TexProperty diffuse;
-        TexProperty specular;
-        TexProperty emission;
-        Ref<Texture> normal;
+    struct PbrMetallicRoughness
+    {
+        vec4 baseColorFactor;
+        TextureInfo baseColorTexture;
+        TextureInfo metallicRoughnessTexture;
+        float metallicFactor;
+        float roughnessFactor;
+    };
+
+    struct PbrSpecularGlossiness
+    {
+        vec4 diffuseFactor;
+        vec3 specularFactor;
+        float glossinessFactor;
+        TextureInfo diffuseTexture;
+		TextureInfo specularGlossinessTexture;
+
+		PbrSpecularGlossiness() { SetDefaults(); }
+		void SetDefaults();
+    };
 
+    //! The material appearance of a primitive.
+    struct Material : public Object
+    {
+        //PBR metallic roughness properties
+        PbrMetallicRoughness pbrMetallicRoughness;
+
+        //other basic material properties
+        NormalTextureInfo normalTexture;
+        OcclusionTextureInfo occlusionTexture;
+        TextureInfo emissiveTexture;
+        vec3 emissiveFactor;
+        std::string alphaMode;
+        float alphaCutoff;
         bool doubleSided;
-        bool transparent;
-        float transparency;
-        float shininess;
 
-        Technique technique;
+        //extension: KHR_materials_pbrSpecularGlossiness
+        Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness;
 
         Material() { SetDefaults(); }
         void Read(Value& obj, Asset& r);
@@ -729,92 +767,21 @@ namespace glTF2
             Ref<Material> material;
         };
 
-		/// \struct SExtension
-		/// Extension used for mesh.
-		struct SExtension
-		{
-			/// \enum EType
-			/// Type of extension.
-			enum EType
-			{
-				#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-					Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorithm.
-				#endif
-
-				Unknown
-			};
-
-			EType Type;///< Type of extension.
-
-			/// \fn SExtension
-			/// Constructor.
-			/// \param [in] pType - type of extension.
-			SExtension(const EType pType)
-				: Type(pType)
-			{}
-
-            virtual ~SExtension() {
-                // empty
-            }
-		};
-
-		#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-			/// \struct SCompression_Open3DGC
-			/// Compression of mesh data using Open3DGC algorithm.
-			struct SCompression_Open3DGC : public SExtension
-			{
-				using SExtension::Type;
-
-				std::string Buffer;///< ID of "buffer" used for storing compressed data.
-				size_t Offset;///< Offset in "bufferView" where compressed data are stored.
-				size_t Count;///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type".
-				bool Binary;///< If true then "binary" mode is used for coding, if false - "ascii" mode.
-				size_t IndicesCount;///< Count of indices in mesh.
-				size_t VerticesCount;///< Count of vertices in mesh.
-				// AttribType::Value Type;///< Is always "SCALAR".
-				// ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121).
-
-				/// \fn SCompression_Open3DGC
-				/// Constructor.
-				SCompression_Open3DGC()
-				: SExtension(Compression_Open3DGC) {
-                    // empty
-                }
-
-                virtual ~SCompression_Open3DGC() {
-                    // empty
-                }
-			};
-		#endif
-
         std::vector<Primitive> primitives;
-		std::list<SExtension*> Extension;///< List of extensions used in mesh.
 
         Mesh() {}
 
-		/// \fn ~Mesh()
-		/// Destructor.
-		~Mesh() { for(std::list<SExtension*>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; }
-
 		/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
 		/// Get mesh data from JSON-object and place them to root asset.
 		/// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
 		/// \param [out] pAsset_Root - reference to root assed where data will be stored.
 		void Read(Value& pJSON_Object, Asset& pAsset_Root);
-
-		#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-			/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
-			/// Decode part of "buffer" which encoded with Open3DGC algorithm.
-			/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
-			/// \param [out] pAsset_Root - reference to root assed where data will be stored.
-			void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root);
-		#endif
     };
 
     struct Node : public Object
     {
         std::vector< Ref<Node> > children;
-        std::vector< Ref<Mesh> > meshes;
+        Ref<Mesh> mesh;
 
         Nullable<mat4> matrix;
         Nullable<vec3> translation;
@@ -822,10 +789,9 @@ namespace glTF2
         Nullable<vec3> scale;
 
         Ref<Camera> camera;
-        Ref<Light>  light;
 
         std::vector< Ref<Node> > skeletons;       //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy.
-        Ref<Skin>  skin;                          //!< The ID of the skin referenced by this node.
+        Ref<Skin> skin;                           //!< The ID of the skin referenced by this node.
         std::string jointName;                    //!< Name used when this node is a joint in a skin.
 
         Ref<Node> parent;                         //!< This is not part of the glTF specification. Used as a helper.
@@ -843,12 +809,12 @@ namespace glTF2
 
     struct Sampler : public Object
     {
-        SamplerMagFilter magFilter; //!< The texture magnification filter. (required)
-        SamplerMinFilter minFilter; //!< The texture minification filter. (required)
-        SamplerWrap wrapS;          //!< The texture wrapping in the S direction. (required)
-        SamplerWrap wrapT;          //!< The texture wrapping in the T direction. (required)
+        SamplerMagFilter magFilter; //!< The texture magnification filter.
+        SamplerMinFilter minFilter; //!< The texture minification filter.
+        SamplerWrap wrapS;          //!< The texture wrapping in the S direction.
+        SamplerWrap wrapT;          //!< The texture wrapping in the T direction.
 
-        Sampler() {}
+        Sampler() { SetDefaults(); }
         void Read(Value& obj, Asset& r);
         void SetDefaults();
     };
@@ -878,27 +844,6 @@ namespace glTF2
         void Read(Value& obj, Asset& r);
     };
 
-    struct Technique : public Object
-    {
-        struct Parameters
-        {
-
-        };
-
-        struct States
-        {
-
-        };
-
-        struct Functions
-        {
-
-        };
-
-        Technique() {}
-        void Read(Value& obj, Asset& r);
-    };
-
     //! A texture and its sampler.
     struct Texture : public Object
     {
@@ -915,35 +860,6 @@ namespace glTF2
         void Read(Value& obj, Asset& r);
     };
 
-
-    //! A light (from KHR_materials_common extension)
-    struct Light : public Object
-    {
-        enum Type
-        {
-            Type_undefined,
-            Type_ambient,
-            Type_directional,
-            Type_point,
-            Type_spot
-        };
-
-        Type type;
-
-        vec4 color;
-        float distance;
-        float constantAttenuation;
-        float linearAttenuation;
-        float quadraticAttenuation;
-        float falloffAngle;
-        float falloffExponent;
-
-        Light() {}
-        void Read(Value& obj, Asset& r);
-
-        void SetDefaults();
-    };
-
     struct Animation : public Object
     {
         struct AnimSampler {
@@ -1025,14 +941,16 @@ namespace glTF2
         friend class Asset;
         friend class AssetWriter;
 
-        typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict;
+        typedef typename std::gltf_unordered_map< unsigned int, unsigned int > Dict;
+        typedef typename std::gltf_unordered_map< std::string, unsigned int > IdDict;
 
-        std::vector<T*>  mObjs;      //! The read objects
-        Dict             mObjsById;  //! The read objects accessible by id
-        const char*      mDictId;    //! ID of the dictionary object
-        const char*      mExtId;     //! ID of the extension defining the dictionary
-        Value*           mDict;      //! JSON dictionary object
-        Asset&           mAsset;     //! The asset instance
+        std::vector<T*>     mObjs;         //! The read objects
+        Dict                mObjsByOIndex; //! The read objects accessible by original index
+        IdDict              mObjsById;     //! The read objects accessible by id
+        const char*         mDictId;       //! ID of the dictionary object
+        const char*         mExtId;        //! ID of the extension defining the dictionary
+        Value*              mDict;         //! JSON dictionary object
+        Asset&              mAsset;        //! The asset instance
 
         void AttachToDocument(Document& doc);
         void DetachFromDocument();
@@ -1046,9 +964,10 @@ namespace glTF2
         LazyDict(Asset& asset, const char* dictId, const char* extId = 0);
         ~LazyDict();
 
-        Ref<T> Get(const char* id);
+        Ref<T> Retrieve(unsigned int i);
+
         Ref<T> Get(unsigned int i);
-        Ref<T> Get(const std::string& pID) { return Get(pID.c_str()); }
+        Ref<T> Get(const char* id);
 
         Ref<T> Create(const char* id);
         Ref<T> Create(const std::string& id)
@@ -1067,22 +986,17 @@ namespace glTF2
     {
         std::string copyright; //!< A copyright message suitable for display to credit the content creator.
         std::string generator; //!< Tool that generated this glTF model.Useful for debugging.
-        bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false)
 
         struct {
             std::string api;     //!< Specifies the target rendering API (default: "WebGL")
             std::string version; //!< Specifies the target rendering API (default: "1.0.3")
         } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
 
-        float version; //!< The glTF format version
+        std::string version; //!< The glTF format version
 
         void Read(Document& doc);
 
-        AssetMetadata()
-            : premultipliedAlpha(false)
-            , version(0)
-        {
-        }
+        AssetMetadata() : version("") {}
     };
 
     //
@@ -1123,8 +1037,7 @@ namespace glTF2
         //! Keeps info about the enabled extensions
         struct Extensions
         {
-            bool KHR_binary_glTF;
-            bool KHR_materials_common;
+            bool KHR_materials_pbrSpecularGlossiness;
 
         } extensionsUsed;
 
@@ -1142,16 +1055,11 @@ namespace glTF2
         LazyDict<Material>    materials;
         LazyDict<Mesh>        meshes;
         LazyDict<Node>        nodes;
-        //LazyDict<Program>   programs;
         LazyDict<Sampler>     samplers;
         LazyDict<Scene>       scenes;
-        //LazyDict<Shader>    shaders;
-        LazyDict<Skin>      skins;
-        //LazyDict<Technique> techniques;
+        LazyDict<Skin>        skins;
         LazyDict<Texture>     textures;
 
-        LazyDict<Light>       lights; // KHR_materials_common ext
-
         Ref<Scene> scene;
 
     public:
@@ -1167,23 +1075,16 @@ namespace glTF2
             , materials     (*this, "materials")
             , meshes        (*this, "meshes")
             , nodes         (*this, "nodes")
-            //, programs    (*this, "programs")
             , samplers      (*this, "samplers")
             , scenes        (*this, "scenes")
-            //, shaders     (*this, "shaders")
-            , skins       (*this, "skins")
-            //, techniques  (*this, "techniques")
+            , skins         (*this, "skins")
             , textures      (*this, "textures")
-            , lights        (*this, "lights", "KHR_materials_common")
         {
             memset(&extensionsUsed, 0, sizeof(extensionsUsed));
         }
 
         //! Main function
-        void Load(const std::string& file, bool isBinary = false);
-
-        //! Enables the "KHR_binary_glTF" extension on the asset
-        void SetAsBinary();
+        void Load(const std::string& file);
 
         //! Search for an available name, starting from the given strings
         std::string FindUniqueID(const std::string& str, const char* suffix);
@@ -1192,11 +1093,8 @@ namespace glTF2
             { return mBodyBuffer; }
 
     private:
-        void ReadBinaryHeader(IOStream& stream);
-
         void ReadExtensionsUsed(Document& doc);
 
-
         IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
     };
 

+ 199 - 523
code/glTF2Asset.inl

@@ -1,4 +1,4 @@
-/*
+/*
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
@@ -44,11 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // Header files, Assimp
 #include <assimp/DefaultLogger.hpp>
 
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-	// Header files, Open3DGC.
-#	include <Open3DGC/o3dgcSC3DMCDecoder.h>
-#endif
-
 using namespace Assimp;
 
 namespace glTF2 {
@@ -128,6 +123,18 @@ namespace {
         return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
     }
 
+    inline Value* FindNumber(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0;
+    }
+
+    inline Value* FindUInt(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd() && it->value.IsUint()) ? &it->value : 0;
+    }
+
     inline Value* FindArray(Value& val, const char* id)
     {
         Value::MemberIterator it = val.FindMember(id);
@@ -176,7 +183,7 @@ inline void LazyDict<T>::AttachToDocument(Document& doc)
     }
 
     if (container) {
-        mDict = FindObject(*container, mDictId);
+        mDict = FindArray(*container, mDictId);
     }
 }
 
@@ -187,18 +194,11 @@ inline void LazyDict<T>::DetachFromDocument()
 }
 
 template<class T>
-Ref<T> LazyDict<T>::Get(unsigned int i)
-{
-    return Ref<T>(mObjs, i);
-}
-
-template<class T>
-Ref<T> LazyDict<T>::Get(const char* id)
+Ref<T> LazyDict<T>::Retrieve(unsigned int i)
 {
-    id = T::TranslateId(mAsset, id);
 
-    typename Dict::iterator it = mObjsById.find(id);
-    if (it != mObjsById.end()) { // already created?
+    typename Dict::iterator it = mObjsByOIndex.find(i);
+    if (it != mObjsByOIndex.end()) {// already created?
         return Ref<T>(mObjs, it->second);
     }
 
@@ -207,27 +207,52 @@ Ref<T> LazyDict<T>::Get(const char* id)
         throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\"");
     }
 
-    Value::MemberIterator obj = mDict->FindMember(id);
-    if (obj == mDict->MemberEnd()) {
-        throw DeadlyImportError("GLTF: Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\"");
+    if (!mDict->IsArray()) {
+        throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\"");
     }
-    if (!obj->value.IsObject()) {
-        throw DeadlyImportError("GLTF: Object with id \"" + std::string(id) + "\" is not a JSON object");
+
+    Value &obj = (*mDict)[i];
+
+    if (!obj.IsObject()) {
+        throw DeadlyImportError("GLTF: Object at index \"" + std::to_string(i) + "\" is not a JSON object");
     }
 
-    // create an instance of the given type
     T* inst = new T();
-    inst->id = id;
-    ReadMember(obj->value, "name", inst->name);
-    inst->Read(obj->value, mAsset);
+    inst->id = std::string(mDictId) + "_" + std::to_string(i);
+    inst->oIndex = i;
+    ReadMember(obj, "name", inst->name);
+    inst->Read(obj, mAsset);
+
     return Add(inst);
 }
 
+template<class T>
+Ref<T> LazyDict<T>::Get(unsigned int i)
+{
+
+    return Ref<T>(mObjs, i);
+
+}
+
+template<class T>
+Ref<T> LazyDict<T>::Get(const char* id)
+{
+    id = T::TranslateId(mAsset, id);
+
+    typename IdDict::iterator it = mObjsById.find(id);
+    if (it != mObjsById.end()) { // already created?
+        return Ref<T>(mObjs, it->second);
+    }
+
+    return Ref<T>();
+}
+
 template<class T>
 Ref<T> LazyDict<T>::Add(T* obj)
 {
     unsigned int idx = unsigned(mObjs.size());
     mObjs.push_back(obj);
+    mObjsByOIndex[obj->oIndex] = idx;
     mObjsById[obj->id] = idx;
     mAsset.mUsedIds[obj->id] = true;
     return Ref<T>(mObjs, idx);
@@ -241,8 +266,10 @@ Ref<T> LazyDict<T>::Create(const char* id)
         throw DeadlyImportError("GLTF: two objects with the same ID exist");
     }
     T* inst = new T();
+    unsigned int idx = unsigned(mObjs.size());
     inst->id = id;
-    inst->index = mObjs.size();
+    inst->index = idx;
+    inst->oIndex = idx;
     return Add(inst);
 }
 
@@ -263,11 +290,6 @@ inline Buffer::~Buffer()
 
 inline const char* Buffer::TranslateId(Asset& r, const char* id)
 {
-    // Compatibility with old spec
-    if (r.extensionsUsed.KHR_binary_glTF && strcmp(id, "KHR_binary_glTF") == 0) {
-        return "binary_glTF";
-    }
-
     return id;
 }
 
@@ -310,7 +332,9 @@ inline void Buffer::Read(Value& obj, Asset& r)
     }
     else { // Local file
         if (byteLength > 0) {
-            IOStream* file = r.OpenFile(uri, "rb");
+            std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : "";
+
+            IOStream* file = r.OpenFile(dir + uri, "rb");
             if (file) {
                 bool ok = LoadFromStream(*file, byteLength);
                 delete file;
@@ -437,9 +461,9 @@ inline void Buffer::Grow(size_t amount)
 
 inline void BufferView::Read(Value& obj, Asset& r)
 {
-    const char* bufferId = MemberOrDefault<const char*>(obj, "buffer", 0);
-    if (bufferId) {
-        buffer = r.buffers.Get(bufferId);
+
+    if (Value* bufferVal = FindUInt(obj, "buffer")) {
+        buffer = r.buffers.Retrieve(bufferVal->GetUint());
     }
 
     byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
@@ -452,9 +476,9 @@ inline void BufferView::Read(Value& obj, Asset& r)
 
 inline void Accessor::Read(Value& obj, Asset& r)
 {
-    const char* bufferViewId = MemberOrDefault<const char*>(obj, "bufferView", 0);
-    if (bufferViewId) {
-        bufferView = r.bufferViews.Get(bufferViewId);
+
+    if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
+        bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
     }
 
     byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
@@ -601,29 +625,6 @@ inline Image::Image()
 
 inline void Image::Read(Value& obj, Asset& r)
 {
-    // Check for extensions first (to detect binary embedded data)
-    if (Value* extensions = FindObject(obj, "extensions")) {
-        if (r.extensionsUsed.KHR_binary_glTF) {
-            if (Value* ext = FindObject(*extensions, "KHR_binary_glTF")) {
-
-                width  = MemberOrDefault(*ext, "width", 0);
-                height = MemberOrDefault(*ext, "height", 0);
-
-                ReadMember(*ext, "mimeType", mimeType);
-
-                const char* bufferViewId;
-                if (ReadMember(*ext, "bufferView", bufferViewId)) {
-                    Ref<BufferView> bv = r.bufferViews.Get(bufferViewId);
-                    if (bv) {
-                        mDataLength = bv->byteLength;
-                        mData = new uint8_t[mDataLength];
-                        memcpy(mData, bv->buffer->GetPointer() + bv->byteOffset, mDataLength);
-                    }
-                }
-            }
-        }
-    }
-
     if (!mDataLength) {
         if (Value* uri = FindString(obj, "uri")) {
             const char* uristr = uri->GetString();
@@ -671,6 +672,7 @@ inline void Sampler::Read(Value& obj, Asset& r)
 {
     SetDefaults();
 
+    ReadMember(obj, "name", name);
     ReadMember(obj, "magFilter", magFilter);
     ReadMember(obj, "minFilter", minFilter);
     ReadMember(obj, "wrapS", wrapS);
@@ -679,34 +681,61 @@ inline void Sampler::Read(Value& obj, Asset& r)
 
 inline void Sampler::SetDefaults()
 {
-    magFilter = SamplerMagFilter_Linear;
-    minFilter = SamplerMinFilter_Linear;
-    wrapS = SamplerWrap_Repeat;
-    wrapT = SamplerWrap_Repeat;
+    //only wrapping modes have defaults
+    wrapS = SamplerWrap::Repeat;
+    wrapT = SamplerWrap::Repeat;
+    magFilter = SamplerMagFilter::UNSET;
+    minFilter = SamplerMinFilter::UNSET;
 }
 
 inline void Texture::Read(Value& obj, Asset& r)
 {
-    const char* sourcestr;
-    if (ReadMember(obj, "source", sourcestr)) {
-        source = r.images.Get(sourcestr);
+    if (Value* sourceVal = FindUInt(obj, "source")) {
+        source = r.images.Retrieve(sourceVal->GetUint());
     }
 
-    const char* samplerstr;
-    if (ReadMember(obj, "sampler", samplerstr)) {
-        sampler = r.samplers.Get(samplerstr);
+    if (Value* samplerVal = FindUInt(obj, "sampler")) {
+        sampler = r.samplers.Retrieve(samplerVal->GetUint());
     }
 }
 
 namespace {
-    inline void ReadMaterialProperty(Asset& r, Value& vals, const char* propName, TexProperty& out)
+    inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out)
+    {
+        if (Value* index = FindUInt(*prop, "index")) {
+            out.texture = r.textures.Retrieve(index->GetUint());
+        }
+
+        if (Value* texcoord = FindUInt(*prop, "texCoord")) {
+            out.texCoord = texcoord->GetUint();
+        }
+    }
+
+    inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, TextureInfo& out)
     {
         if (Value* prop = FindMember(vals, propName)) {
-            if (prop->IsString()) {
-                out.texture = r.textures.Get(prop->GetString());
+            SetTextureProperties(r, prop, out);
+        }
+    }
+
+    inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, NormalTextureInfo& out)
+    {
+        if (Value* prop = FindMember(vals, propName)) {
+            SetTextureProperties(r, prop, out);
+
+            if (Value* scale = FindNumber(*prop, "scale")) {
+                out.scale = scale->GetDouble();
             }
-            else {
-                ReadValue(*prop, out.color);
+        }
+    }
+
+    inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, OcclusionTextureInfo& out)
+    {
+        if (Value* prop = FindMember(vals, propName)) {
+            SetTextureProperties(r, prop, out);
+
+            if (Value* strength = FindNumber(*prop, "strength")) {
+                out.strength = strength->GetDouble();
             }
         }
     }
@@ -716,59 +745,67 @@ inline void Material::Read(Value& material, Asset& r)
 {
     SetDefaults();
 
-    if (Value* values = FindObject(material, "values")) {
-        ReadMaterialProperty(r, *values, "ambient", this->ambient);
-        ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
-        ReadMaterialProperty(r, *values, "specular", this->specular);
-
-        ReadMember(*values, "transparency", transparency);
-        ReadMember(*values, "shininess", shininess);
+    if (Value* pbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
+        ReadMember(*pbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
+        ReadTextureProperty(r, *pbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
+        ReadTextureProperty(r, *pbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
+        ReadMember(*pbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
+        ReadMember(*pbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
     }
 
+    ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
+    ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
+    ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
+    ReadMember(material, "emissiveFactor", this->emissiveFactor);
+
+    ReadMember(material, "doubleSided", this->doubleSided);
+    ReadMember(material, "alphaMode", this->alphaMode);
+    ReadMember(material, "alphaCutoff", this->alphaCutoff);
+
     if (Value* extensions = FindObject(material, "extensions")) {
-        if (r.extensionsUsed.KHR_materials_common) {
-            if (Value* ext = FindObject(*extensions, "KHR_materials_common")) {
-                if (Value* tnq = FindString(*ext, "technique")) {
-                    const char* t = tnq->GetString();
-                    if      (strcmp(t, "BLINN") == 0)    technique = Technique_BLINN;
-                    else if (strcmp(t, "PHONG") == 0)    technique = Technique_PHONG;
-                    else if (strcmp(t, "LAMBERT") == 0)  technique = Technique_LAMBERT;
-                    else if (strcmp(t, "CONSTANT") == 0) technique = Technique_CONSTANT;
-                }
+        if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
+            if (Value* pbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
+                PbrSpecularGlossiness pbrSG;
 
-                if (Value* values = FindObject(*ext, "values")) {
-                    ReadMaterialProperty(r, *values, "ambient", this->ambient);
-                    ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
-                    ReadMaterialProperty(r, *values, "specular", this->specular);
+                ReadMember(*pbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
+                ReadTextureProperty(r, *pbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
+                ReadTextureProperty(r, *pbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
+                ReadMember(*pbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
+                ReadMember(*pbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
 
-                    ReadMember(*values, "doubleSided", doubleSided);
-                    ReadMember(*values, "transparent", transparent);
-                    ReadMember(*values, "transparency", transparency);
-                    ReadMember(*values, "shininess", shininess);
-                }
+                this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
             }
         }
     }
 }
 
 namespace {
-    void SetVector(vec4& v, float x, float y, float z, float w)
-        { v[0] = x; v[1] = y; v[2] = z; v[3] = w; }
+    void SetVector(vec4& v, const float(&in)[4])
+        { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; v[3] = in[3]; }
+
+    void SetVector(vec3& v, const float(&in)[3])
+        { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; }
 }
 
 inline void Material::SetDefaults()
 {
-    SetVector(ambient.color, 0, 0, 0, 1);
-    SetVector(diffuse.color, 0, 0, 0, 1);
-    SetVector(specular.color, 0, 0, 0, 1);
-    SetVector(emission.color, 0, 0, 0, 1);
-
+    //pbr materials
+    SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
+    pbrMetallicRoughness.metallicFactor = 1.0;
+    pbrMetallicRoughness.roughnessFactor = 1.0;
+
+    SetVector(emissiveFactor, defaultEmissiveFactor);
+    alphaMode = "OPAQUE";
+    alphaCutoff = 0.5;
     doubleSided = false;
-    transparent = false;
-    transparency = 1.0;
-    shininess = 0.0;
+}
 
-    technique = Technique_undefined;
+inline void PbrSpecularGlossiness::SetDefaults()
+{
+    //pbrSpecularGlossiness properties
+    SetVector(diffuseFactor, defaultDiffuseFactor);
+    SetVector(specularFactor, defaultSpecularFactor);
+    glossinessFactor = 1.0;
 }
 
 namespace {
@@ -808,6 +845,10 @@ namespace {
 
 inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
 {
+    if (Value* name = FindMember(pJSON_Object, "name")) {
+        this->name = name->GetString();
+    }
+
 	/****************** Mesh primitives ******************/
 	if (Value* primitives = FindArray(pJSON_Object, "primitives")) {
         this->primitives.resize(primitives->Size());
@@ -819,7 +860,7 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
 
             if (Value* attrs = FindObject(primitive, "attributes")) {
                 for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
-                    if (!it->value.IsString()) continue;
+                    if (!it->value.IsUint()) continue;
                     const char* attr = it->name.GetString();
                     // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
                     // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
@@ -829,262 +870,22 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
                     if (GetAttribVector(prim, attr, vec, undPos)) {
                         size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
                         if ((*vec).size() <= idx) (*vec).resize(idx + 1);
-						(*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString());
+						(*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
                     }
                 }
             }
 
-            if (Value* indices = FindString(primitive, "indices")) {
-				prim.indices = pAsset_Root.accessors.Get(indices->GetString());
+            if (Value* indices = FindUInt(primitive, "indices")) {
+				prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
             }
 
-            if (Value* material = FindString(primitive, "material")) {
-				prim.material = pAsset_Root.materials.Get(material->GetString());
+            if (Value* material = FindUInt(primitive, "material")) {
+				prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
             }
         }
     }
-
-	/****************** Mesh extensions ******************/
-	Value* json_extensions = FindObject(pJSON_Object, "extensions");
-
-	if(json_extensions == nullptr) goto mr_skip_extensions;
-
-	for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++)
-	{
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-        if(it_memb->name.GetString() == std::string("Open3DGC-compression"))
-		{
-			// Search for compressed data.
-			// Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
-			// new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure.
-			Value* comp_data = FindObject(it_memb->value, "compressedData");
-
-			if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\".");
-
-			DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data.");
-
-			/************** Read data from JSON-document **************/
-			#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
-				if(!ReadMember(*comp_data, pFieldName, pOut)) \
-				{ \
-					throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); \
-				}
-
-			const char* mode_str;
-			const char* type_str;
-			ComponentType component_type;
-			SCompression_Open3DGC* ext_o3dgc = new SCompression_Open3DGC;
-
-			MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer);
-			MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset);
-			MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type);
-			MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str);
-			MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count);
-			MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str);
-			MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount);
-			MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount);
-
-			#undef MESH_READ_COMPRESSEDDATA_MEMBER
-
-			// Check some values
-			if(strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data.");
-			if(component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data.");
-
-			// Set read/write data mode.
-			if(strcmp(mode_str, "binary") == 0)
-				ext_o3dgc->Binary = true;
-			else if(strcmp(mode_str, "ascii") == 0)
-				ext_o3dgc->Binary = false;
-			else
-				throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\".");
-
-			/************************ Decoding ************************/
-			Decode_O3DGC(*ext_o3dgc, pAsset_Root);
-			Extension.push_back(ext_o3dgc);// store info in mesh extensions list.
-		}// if(it_memb->name.GetString() == "Open3DGC-compression")
-		else
-#endif
-		{
-			throw DeadlyImportError(std::string("GLTF: Unknown mesh extension: \"") + it_memb->name.GetString() + "\".");
-		}
-	}// for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
-
-mr_skip_extensions:
-
-	return;// After label some operators must be present.
 }
 
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
-{
-typedef unsigned short IndicesType;///< \sa glTFExporter::ExportMeshes.
-
-o3dgc::SC3DMCDecoder<IndicesType> decoder;
-o3dgc::IndexedFaceSet<IndicesType> ifs;
-o3dgc::BinaryStream bstream;
-uint8_t* decoded_data;
-size_t decoded_data_size = 0;
-Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
-
-	// Read data from buffer and place it in BinaryStream for decoder.
-	// Just "Count" because always is used type equivalent to uint8_t.
-	bstream.LoadFromBuffer(&buf->GetPointer()[pCompression_Open3DGC.Offset], static_cast<unsigned long>(pCompression_Open3DGC.Count));
-
-	// After decoding header we can get size of primitives.
-	if(decoder.DecodeHeader(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC header.");
-
-	/****************** Get sizes of arrays and check sizes ******************/
-	// Note. See "Limitations for meshes when using Open3DGC-compression".
-
-	// Indices
-	size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note.
-
-	if(primitives[0].indices->count != size_coordindex)
-		throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + std::to_string(size_coordindex) +
-								") not equal to uncompressed (" + std::to_string(primitives[0].indices->count) + ").");
-
-	size_coordindex *= sizeof(IndicesType);
-	// Coordinates
-	size_t size_coord = ifs.GetNCoord();// See float attributes note.
-
-	if(primitives[0].attributes.position[0]->count != size_coord)
-		throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + std::to_string(size_coord) +
-								") not equal to uncompressed (" + std::to_string(primitives[0].attributes.position[0]->count) + ").");
-
-	size_coord *= 3 * sizeof(float);
-	// Normals
-	size_t size_normal = ifs.GetNNormal();// See float attributes note.
-
-	if(primitives[0].attributes.normal[0]->count != size_normal)
-		throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + std::to_string(size_normal) +
-								") not equal to uncompressed (" + std::to_string(primitives[0].attributes.normal[0]->count) + ").");
-
-	size_normal *= 3 * sizeof(float);
-	// Additional attributes.
-	std::vector<size_t> size_floatattr;
-	std::vector<size_t> size_intattr;
-
-	size_floatattr.resize(ifs.GetNumFloatAttributes());
-	size_intattr.resize(ifs.GetNumIntAttributes());
-
-	decoded_data_size = size_coordindex + size_coord + size_normal;
-	for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++)
-	{
-		// size = number_of_elements * components_per_element * size_of_component.
-		// Note. But as you can see above, at first we are use this variable in meaning "count". After checking count of objects...
-		size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx));
-
-		switch(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))
-		{
-			case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
-				// Check situation when encoded data contain texture coordinates but primitive not.
-				if(idx_texcoord < primitives[0].attributes.texcoord.size())
-				{
-					if(primitives[0].attributes.texcoord[idx]->count != tval)
-						throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + std::to_string(tval) +
-												") not equal to uncompressed (" + std::to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
-
-					idx_texcoord++;
-				}
-				else
-				{
-					ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul);// Disable decoding this attribute.
-				}
-
-				break;
-			default:
-				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
-		}
-
-		tval *=  ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real);// After checking count of objects we can get size of array.
-		size_floatattr[idx] = tval;
-		decoded_data_size += tval;
-	}
-
-	for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++)
-	{
-		// size = number_of_elements * components_per_element * size_of_component. See float attributes note.
-		size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx));
-		switch( ifs.GetIntAttributeType(static_cast<unsigned long>(idx) ) )
-		{
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
-                break;
-
-			default:
-				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
-		}
-
-		tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long);// See float attributes note.
-		size_intattr[idx] = tval;
-		decoded_data_size += tval;
-	}
-
-	// Create array for decoded data.
-	decoded_data = new uint8_t[decoded_data_size];
-
-	/****************** Set right array regions for decoder ******************/
-
-	auto get_buf_offset = [](Ref<Accessor>& pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; };
-
-	// Indices
-	ifs.SetCoordIndex((IndicesType* const)(decoded_data + get_buf_offset(primitives[0].indices)));
-	// Coordinates
-	ifs.SetCoord((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.position[0])));
-	// Normals
-	if(size_normal)
-	{
-		ifs.SetNormal((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0])));
-	}
-
-	for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++)
-	{
-		switch(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))
-		{
-			case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
-				if(idx_texcoord < primitives[0].attributes.texcoord.size())
-				{
-					// See above about absent attributes.
-					ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
-					idx_texcoord++;
-				}
-
-				break;
-			default:
-				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
-		}
-	}
-
-	for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
-		switch(ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) {
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
-            case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
-                break;
-
-			// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
-			default:
-				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
-		}
-	}
-
-	//
-	// Decode data
-	//
-    if ( decoder.DecodePayload( ifs, bstream ) != o3dgc::O3DGC_OK ) {
-        throw DeadlyImportError( "GLTF: can not decode Open3DGC data." );
-    }
-
-	// Set encoded region for "buffer".
-	buf->EncodedRegion_Mark(pCompression_Open3DGC.Offset, pCompression_Open3DGC.Count, decoded_data, decoded_data_size, id);
-	// No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data".
-	// "delete [] output_data;"
-}
-#endif
-
 inline void Camera::Read(Value& obj, Asset& r)
 {
     type = MemberOrDefault(obj, "type", Camera::Perspective);
@@ -1095,80 +896,34 @@ inline void Camera::Read(Value& obj, Asset& r)
     if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
 
     if (type == Camera::Perspective) {
-        perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
-        perspective.yfov        = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
-        perspective.zfar        = MemberOrDefault(*it, "zfar", 100.f);
-        perspective.znear       = MemberOrDefault(*it, "znear", 0.01f);
+        cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
+        cameraProperties.perspective.yfov        = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
+        cameraProperties.perspective.zfar        = MemberOrDefault(*it, "zfar", 100.f);
+        cameraProperties.perspective.znear       = MemberOrDefault(*it, "znear", 0.01f);
     }
     else {
-        ortographic.xmag  = MemberOrDefault(obj, "xmag", 1.f);
-        ortographic.ymag  = MemberOrDefault(obj, "ymag", 1.f);
-        ortographic.zfar  = MemberOrDefault(obj, "zfar", 100.f);
-        ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
+        cameraProperties.ortographic.xmag  = MemberOrDefault(obj, "xmag", 1.f);
+        cameraProperties.ortographic.ymag  = MemberOrDefault(obj, "ymag", 1.f);
+        cameraProperties.ortographic.zfar  = MemberOrDefault(obj, "zfar", 100.f);
+        cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
     }
 }
 
-inline void Light::Read(Value& obj, Asset& r)
-{
-    SetDefaults();
-
-    if (Value* type = FindString(obj, "type")) {
-        const char* t = type->GetString();
-        if      (strcmp(t, "ambient") == 0)     this->type = Type_ambient;
-        else if (strcmp(t, "directional") == 0) this->type = Type_directional;
-        else if (strcmp(t, "point") == 0)       this->type = Type_point;
-        else if (strcmp(t, "spot") == 0)        this->type = Type_spot;
-
-        if (this->type != Type_undefined) {
-            if (Value* vals = FindString(obj, t)) {
-                ReadMember(*vals, "color", color);
-
-                ReadMember(*vals, "constantAttenuation", constantAttenuation);
-                ReadMember(*vals, "linearAttenuation", linearAttenuation);
-                ReadMember(*vals, "quadraticAttenuation", quadraticAttenuation);
-                ReadMember(*vals, "distance", distance);
-
-                ReadMember(*vals, "falloffAngle", falloffAngle);
-                ReadMember(*vals, "falloffExponent", falloffExponent);
-            }
-        }
-    }
-}
-
-inline void Light::SetDefaults()
-{
-    #ifndef M_PI
-        const float M_PI = 3.14159265358979323846f;
-    #endif
-
-    type = Type_undefined;
-
-    SetVector(color, 0.f, 0.f, 0.f, 1.f);
-
-    constantAttenuation = 0.f;
-    linearAttenuation = 1.f;
-    quadraticAttenuation = 1.f;
-    distance = 0.f;
-
-    falloffAngle = static_cast<float>(M_PI / 2.f);
-    falloffExponent = 0.f;
-}
-
 inline void Node::Read(Value& obj, Asset& r)
 {
+
     if (Value* children = FindArray(obj, "children")) {
         this->children.reserve(children->Size());
         for (unsigned int i = 0; i < children->Size(); ++i) {
             Value& child = (*children)[i];
-            if (child.IsString()) {
+            if (child.IsUint()) {
                 // get/create the child node
-                Ref<Node> chn = r.nodes.Get(child.GetString());
+                Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
                 if (chn) this->children.push_back(chn);
             }
         }
     }
 
-
     if (Value* matrix = FindArray(obj, "matrix")) {
         ReadValue(*matrix, this->matrix);
     }
@@ -1178,64 +933,46 @@ inline void Node::Read(Value& obj, Asset& r)
         ReadMember(obj, "rotation", rotation);
     }
 
-    if (Value* meshes = FindArray(obj, "meshes")) {
-        unsigned numMeshes = (unsigned)meshes->Size();
+    if (Value* mesh = FindUInt(obj, "mesh")) {
+        Ref<Mesh> meshRef = r.meshes.Retrieve((*mesh).GetUint());
 
-        std::vector<unsigned int> meshList;
-
-        this->meshes.reserve(numMeshes);
-        for (unsigned i = 0; i < numMeshes; ++i) {
-            if ((*meshes)[i].IsString()) {
-                Ref<Mesh> mesh = r.meshes.Get((*meshes)[i].GetString());
-                if (mesh) this->meshes.push_back(mesh);
-            }
-        }
+        if (meshRef) this->mesh = meshRef;
     }
 
-    if (Value* camera = FindString(obj, "camera")) {
-        this->camera = r.cameras.Get(camera->GetString());
+    if (Value* camera = FindUInt(obj, "camera")) {
+        this->camera = r.cameras.Retrieve(camera->GetUint());
         if (this->camera)
             this->camera->id = this->id;
     }
-
-    // TODO load "skeletons", "skin", "jointName"
-
-    if (Value* extensions = FindObject(obj, "extensions")) {
-        if (r.extensionsUsed.KHR_materials_common) {
-
-            if (Value* ext = FindObject(*extensions, "KHR_materials_common")) {
-                if (Value* light = FindString(*ext, "light")) {
-                    this->light = r.lights.Get(light->GetString());
-                }
-            }
-
-        }
-    }
 }
 
 inline void Scene::Read(Value& obj, Asset& r)
 {
     if (Value* array = FindArray(obj, "nodes")) {
         for (unsigned int i = 0; i < array->Size(); ++i) {
-            if (!(*array)[i].IsString()) continue;
-            Ref<Node> node = r.nodes.Get((*array)[i].GetString());
+            if (!(*array)[i].IsUint()) continue;
+            Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
             if (node)
                 this->nodes.push_back(node);
         }
     }
 }
 
-
 inline void AssetMetadata::Read(Document& doc)
 {
-    // read the version, etc.
-    float statedVersion = 0;
     if (Value* obj = FindObject(doc, "asset")) {
         ReadMember(*obj, "copyright", copyright);
         ReadMember(*obj, "generator", generator);
 
-        premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
-        statedVersion = MemberOrDefault(*obj, "version", 0);
+        if (Value* versionString = FindString(*obj, "version")) {
+            version = versionString->GetString();
+        } else if (Value* versionNumber = FindNumber (*obj, "version")) {
+            char buf[4];
+
+            ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
+
+            version = buf;
+        }
 
         if (Value* profile = FindObject(*obj, "profile")) {
             ReadMember(*profile, "api",     this->profile.api);
@@ -1243,60 +980,16 @@ inline void AssetMetadata::Read(Document& doc)
         }
     }
 
-    version = std::max(statedVersion, version);
-
-    if (version == 0) {
-        // if missing version, we'll assume version 1.0...
-        version = 1;
-    }
-
-    if (version != 1) {
-        char msg[128];
-        ai_snprintf(msg, 128, "GLTF: Unsupported glTF version: %.1f", version);
-        throw DeadlyImportError(msg);
+    if (version.empty() || version[0] != '2') {
+        throw DeadlyImportError("GLTF: Unsupported glTF version: " + version);
     }
 }
 
-
-
 //
 // Asset methods implementation
 //
 
-inline void Asset::ReadBinaryHeader(IOStream& stream)
-{
-    GLB_Header header;
-    if (stream.Read(&header, sizeof(header), 1) != 1) {
-        throw DeadlyImportError("GLTF: Unable to read the file header");
-    }
-
-    if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
-        throw DeadlyImportError("GLTF: Invalid binary glTF file");
-    }
-
-    AI_SWAP4(header.version);
-    asset.version = header.version;
-    if (header.version != 1) {
-        throw DeadlyImportError("GLTF: Unsupported binary glTF version");
-    }
-
-    AI_SWAP4(header.sceneFormat);
-    if (header.sceneFormat != SceneFormat_JSON) {
-        throw DeadlyImportError("GLTF: Unsupported binary glTF scene format");
-    }
-
-    AI_SWAP4(header.length);
-    AI_SWAP4(header.sceneLength);
-
-    mSceneLength = static_cast<size_t>(header.sceneLength);
-
-    mBodyOffset = sizeof(header)+mSceneLength;
-    mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
-
-    mBodyLength = header.length - mBodyOffset;
-}
-
-inline void Asset::Load(const std::string& pFile, bool isBinary)
+inline void Asset::Load(const std::string& pFile)
 {
     mCurrentAssetDir.clear();
     int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
@@ -1307,16 +1000,8 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
         throw DeadlyImportError("GLTF: Could not open file for reading");
     }
 
-    // is binary? then read the header
-    if (isBinary) {
-        SetAsBinary(); // also creates the body buffer
-        ReadBinaryHeader(*stream);
-    }
-    else {
-        mSceneLength = stream->FileSize();
-        mBodyLength = 0;
-    }
-
+    mSceneLength = stream->FileSize();
+    mBodyLength = 0;
 
     // read the scene data
 
@@ -1361,12 +1046,14 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
         mDicts[i]->AttachToDocument(doc);
     }
 
-
-
     // Read the "scene" property, which specifies which scene to load
     // and recursively load everything referenced by it
-    if (Value* scene = FindString(doc, "scene")) {
-        this->scene = scenes.Get(scene->GetString());
+    if (Value* scene = FindUInt(doc, "scene")) {
+        unsigned int sceneIndex = scene->GetUint();
+
+        Ref<Scene> s = scenes.Retrieve(sceneIndex);
+
+        this->scene = s;
     }
 
     // Clean up
@@ -1375,16 +1062,6 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
     }
 }
 
-inline void Asset::SetAsBinary()
-{
-    if (!extensionsUsed.KHR_binary_glTF) {
-        extensionsUsed.KHR_binary_glTF = true;
-        mBodyBuffer = buffers.Create("binary_glTF");
-        mBodyBuffer->MarkAsSpecial();
-    }
-}
-
-
 inline void Asset::ReadExtensionsUsed(Document& doc)
 {
     Value* extsUsed = FindArray(doc, "extensionsUsed");
@@ -1401,8 +1078,7 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
     #define CHECK_EXT(EXT) \
         if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
 
-    CHECK_EXT(KHR_binary_glTF);
-    CHECK_EXT(KHR_materials_common);
+    CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
 
     #undef CHECK_EXT
 }

+ 1 - 3
code/glTF2AssetWriter.h

@@ -43,8 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * Declares a class to write gltf/glb files
  *
  * glTF Extensions Support:
- *   KHR_binary_glTF: full
- *   KHR_materials_common: full
+ *   KHR_materials_pbrSpecularGlossiness: full
  */
 #ifndef GLTF2ASSETWRITER_H_INC
 #define GLTF2ASSETWRITER_H_INC
@@ -82,7 +81,6 @@ public:
     AssetWriter(Asset& asset);
 
     void WriteFile(const char* path);
-    void WriteGLBFile(const char* path);
 };
 
 }

+ 166 - 204
code/glTF2AssetWriter.inl

@@ -72,6 +72,12 @@ namespace glTF2 {
             return val;
         }
 
+        inline Value& MakeValue(Value& val, float r, MemoryPoolAllocator<>& al) {
+            val.SetDouble(r);
+
+            return val;
+        }
+
         template<class T>
         inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
             if (v.empty()) return;
@@ -91,7 +97,11 @@ namespace glTF2 {
     {
         obj.AddMember("bufferView", a.bufferView->index, w.mAl);
         obj.AddMember("byteOffset", a.byteOffset, w.mAl);
-        obj.AddMember("byteStride", a.byteStride, w.mAl);
+
+        if (a.byteStride != 0) {
+            obj.AddMember("byteStride", a.byteStride, w.mAl);
+        }
+
         obj.AddMember("componentType", int(a.componentType), w.mAl);
         obj.AddMember("count", a.count, w.mAl);
         obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
@@ -169,21 +179,7 @@ namespace glTF2 {
     inline void Write(Value& obj, Image& img, AssetWriter& w)
     {
         std::string uri;
-        if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) {
-            Value exts, ext;
-            exts.SetObject();
-            ext.SetObject();
-
-            ext.AddMember("bufferView", img.bufferView->index, w.mAl);
-
-            if (!img.mimeType.empty())
-                ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
-
-            exts.AddMember("KHR_binary_glTF", ext, w.mAl);
-            obj.AddMember("extensions", exts, w.mAl);
-            return;
-        }
-        else if (img.HasData()) {
+        if (img.HasData()) {
             uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
             uri += ";base64,";
             Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri);
@@ -196,51 +192,149 @@ namespace glTF2 {
     }
 
     namespace {
-        inline void WriteTex(Value& obj, Ref<Texture> texture, const char* propName, MemoryPoolAllocator<>& al)
+        inline void SetTexBasic(TextureInfo t, Value& tex, MemoryPoolAllocator<>& al)
+        {
+            tex.SetObject();
+            tex.AddMember("index", t.texture->index, al);
+
+            if (t.texCoord != 0) {
+                tex.AddMember("texCoord", t.texCoord, al);
+            }
+        }
+
+        inline void WriteTex(Value& obj, TextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
+        {
+
+            if (t.texture) {
+                Value tex;
+
+                SetTexBasic(t, tex, al);
+
+                obj.AddMember(StringRef(propName), tex, al);
+            }
+        }
+
+        inline void WriteTex(Value& obj, NormalTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
+        {
+
+            if (t.texture) {
+                Value tex;
+
+                SetTexBasic(t, tex, al);
+
+                if (t.scale != 1) {
+                    tex.AddMember("scale", t.scale, al);
+                }
+
+                obj.AddMember(StringRef(propName), tex, al);
+            }
+        }
+
+        inline void WriteTex(Value& obj, OcclusionTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
         {
-            if (texture) {
+
+            if (t.texture) {
                 Value tex;
-                tex.SetObject();
-                tex.AddMember("index", texture->index, al);
+
+                SetTexBasic(t, tex, al);
+
+                if (t.strength != 1) {
+                    tex.AddMember("strength", t.strength, al);
+                }
+
                 obj.AddMember(StringRef(propName), tex, al);
             }
         }
 
-        inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
+        template<size_t N>
+        inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, MemoryPoolAllocator<>& al)
+        {
+            Value arr;
+            obj.AddMember(StringRef(propName), MakeValue(arr, prop, al), al);
+        }
+
+        template<size_t N>
+        inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, const float(&defaultVal)[N], MemoryPoolAllocator<>& al)
         {
-            WriteTex(obj, prop.texture, propName, al);
-            if (!prop.texture) {
-                Value col;
-                obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
+            if (!std::equal(std::begin(prop), std::end(prop), std::begin(defaultVal))) {
+                WriteVec(obj, prop, propName, al);
             }
         }
+
+        inline void WriteFloat(Value& obj, float prop, const char* propName, MemoryPoolAllocator<>& al)
+        {
+            Value num;
+            obj.AddMember(StringRef(propName), MakeValue(num, prop, al), al);
+        }
     }
 
     inline void Write(Value& obj, Material& m, AssetWriter& w)
     {
-        if (m.transparent) {
-            obj.AddMember("alphaMode", "BLEND", w.mAl);
+        Value pbrMetallicRoughness;
+        pbrMetallicRoughness.SetObject();
+        {
+            WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorTexture, "baseColorTexture", w.mAl);
+            WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicRoughnessTexture, "metallicRoughnessTexture", w.mAl);
+            WriteVec(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorFactor, "baseColorFactor", defaultBaseColor, w.mAl);
+
+            if (m.pbrMetallicRoughness.metallicFactor != 1) {
+                WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicFactor, "metallicFactor", w.mAl);
+            }
+
+            if (m.pbrMetallicRoughness.roughnessFactor != 1) {
+                WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.roughnessFactor, "roughnessFactor", w.mAl);
+            }
         }
 
-        Value v;
-        v.SetObject();
-        {
-            if (m.transparent && !m.diffuse.texture) {
-                m.diffuse.color[3] = m.transparency;
+        if (!pbrMetallicRoughness.ObjectEmpty()) {
+            obj.AddMember("pbrMetallicRoughness", pbrMetallicRoughness, w.mAl);
+        }
+
+        WriteTex(obj, m.normalTexture, "normalTexture", w.mAl);
+        WriteTex(obj, m.emissiveTexture, "emissiveTexture", w.mAl);
+        WriteTex(obj, m.occlusionTexture, "occlusionTexture", w.mAl);
+        WriteVec(obj, m.emissiveFactor, "emissiveFactor", defaultEmissiveFactor, w.mAl);
+
+        if (m.alphaCutoff != 0.5) {
+            WriteFloat(obj, m.alphaCutoff, "alphaCutoff", w.mAl);
+        }
+
+        if (m.alphaMode != "OPAQUE") {
+            obj.AddMember("alphaMode", Value(m.alphaMode, w.mAl).Move(), w.mAl);
+        }
+
+        if (m.doubleSided) {
+            obj.AddMember("doubleSided", m.doubleSided, w.mAl);
+        }
+
+        Value exts;
+        exts.SetObject();
+
+        if (m.pbrSpecularGlossiness.isPresent) {
+            Value pbrSpecularGlossiness;
+            pbrSpecularGlossiness.SetObject();
+
+            PbrSpecularGlossiness &pbrSG = m.pbrSpecularGlossiness.value;
+
+            //pbrSpecularGlossiness
+            WriteVec(pbrSpecularGlossiness, pbrSG.diffuseFactor, "diffuseFactor", defaultDiffuseFactor, w.mAl);
+            WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
+
+            if (pbrSG.glossinessFactor != 1) {
+                WriteFloat(obj, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
             }
-            WriteColorOrTex(v, m.ambient, m.ambient.texture ? "ambientTexture" : "ambientFactor", w.mAl);
-            WriteColorOrTex(v, m.diffuse, m.diffuse.texture ? "diffuseTexture" : "diffuseFactor", w.mAl);
-            WriteColorOrTex(v, m.specular, m.specular.texture ? "specularTexture" : "specularFactor", w.mAl);
-            WriteColorOrTex(v, m.emission, m.emission.texture ? "emissionTexture" : "emissionFactor", w.mAl);
-            v.AddMember("shininessFactor", m.shininess, w.mAl);
-        }
-        v.AddMember("type", "commonPhong", w.mAl);
-        Value ext;
-        ext.SetObject();
-        ext.AddMember("KHR_materials_common", v, w.mAl);
-        obj.AddMember("extensions", ext, w.mAl);
-
-        WriteTex(obj, m.normal, "normalTexture", w.mAl);
+
+            WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
+            WriteTex(pbrSpecularGlossiness, pbrSG.specularGlossinessTexture, "specularGlossinessTexture", w.mAl);
+
+            if (!pbrSpecularGlossiness.ObjectEmpty()) {
+                exts.AddMember("KHR_materials_pbrSpecularGlossiness", pbrSpecularGlossiness, w.mAl);
+            }
+        }
+
+        if (!exts.ObjectEmpty()) {
+            obj.AddMember("extensions", exts, w.mAl);
+        }
     }
 
     namespace {
@@ -263,59 +357,6 @@ namespace glTF2 {
 
     inline void Write(Value& obj, Mesh& m, AssetWriter& w)
     {
-		/********************* Name **********************/
-		obj.AddMember("name", m.name, w.mAl);
-
-		/**************** Mesh extensions ****************/
-		if(m.Extension.size() > 0)
-		{
-			Value json_extensions;
-
-			json_extensions.SetObject();
-			for(Mesh::SExtension* ptr_ext : m.Extension)
-			{
-				switch(ptr_ext->Type)
-				{
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-					case Mesh::SExtension::EType::Compression_Open3DGC:
-						{
-							Value json_comp_data;
-							Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext;
-
-							// filling object "compressedData"
-							json_comp_data.SetObject();
-							json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl);
-							json_comp_data.AddMember("byteOffset", ptr_ext_comp->Offset, w.mAl);
-							json_comp_data.AddMember("componentType", 5121, w.mAl);
-							json_comp_data.AddMember("type", "SCALAR", w.mAl);
-							json_comp_data.AddMember("count", ptr_ext_comp->Count, w.mAl);
-							if(ptr_ext_comp->Binary)
-								json_comp_data.AddMember("mode", "binary", w.mAl);
-							else
-								json_comp_data.AddMember("mode", "ascii", w.mAl);
-
-							json_comp_data.AddMember("indicesCount", ptr_ext_comp->IndicesCount, w.mAl);
-							json_comp_data.AddMember("verticesCount", ptr_ext_comp->VerticesCount, w.mAl);
-							// filling object "Open3DGC-compression"
-							Value json_o3dgc;
-
-							json_o3dgc.SetObject();
-							json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl);
-							// add member to object "extensions"
-							json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl);
-						}
-
-						break;
-#endif
-					default:
-						throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
-				}// switch(ptr_ext->Type)
-			}// for(Mesh::SExtension* ptr_ext : m.Extension)
-
-			// Add extensions to mesh
-			obj.AddMember("extensions", json_extensions, w.mAl);
-		}// if(m.Extension.size() > 0)
-
 		/****************** Primitives *******************/
         Value primitives;
         primitives.SetArray();
@@ -340,10 +381,9 @@ namespace glTF2 {
                     WriteAttrs(w, attrs, p.attributes.position, "POSITION");
                     WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
                     WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
-                    WriteAttrs(w, attrs, p.attributes.color, "COLOR");
-                    WriteAttrs(w, attrs, p.attributes.joint, "JOINT");
-                    WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX");
-                    WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT");
+                    WriteAttrs(w, attrs, p.attributes.color, "COLOR", true);
+                    WriteAttrs(w, attrs, p.attributes.joint, "JOINTS", true);
+                    WriteAttrs(w, attrs, p.attributes.weight, "WEIGHTS", true);
                 }
                 prim.AddMember("attributes", attrs, w.mAl);
             }
@@ -377,7 +417,9 @@ namespace glTF2 {
 
         AddRefsVector(obj, "children", n.children, w.mAl);
 
-        AddRefsVector(obj, "meshes", n.meshes, w.mAl);
+        if (n.mesh) {
+            obj.AddMember("mesh", n.mesh->index, w.mAl);
+        }
 
         AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
 
@@ -397,17 +439,24 @@ namespace glTF2 {
 
     inline void Write(Value& obj, Sampler& b, AssetWriter& w)
     {
-        if (b.wrapS) {
-            obj.AddMember("wrapS", b.wrapS, w.mAl);
+        if (!b.name.empty()) {
+            obj.AddMember("name", b.name, w.mAl);
         }
-        if (b.wrapT) {
-            obj.AddMember("wrapT", b.wrapT, w.mAl);
+
+        if (b.wrapS != SamplerWrap::UNSET && b.wrapS != SamplerWrap::Repeat) {
+            obj.AddMember("wrapS", static_cast<unsigned int>(b.wrapS), w.mAl);
         }
-        if (b.magFilter) {
-            obj.AddMember("magFilter", b.magFilter, w.mAl);
+
+        if (b.wrapT != SamplerWrap::UNSET && b.wrapT != SamplerWrap::Repeat) {
+            obj.AddMember("wrapT", static_cast<unsigned int>(b.wrapT), w.mAl);
         }
-        if (b.minFilter) {
-            obj.AddMember("minFilter", b.minFilter, w.mAl);
+
+        if (b.magFilter != SamplerMagFilter::UNSET) {
+            obj.AddMember("magFilter", static_cast<unsigned int>(b.magFilter), w.mAl);
+        }
+
+        if (b.minFilter != SamplerMinFilter::UNSET) {
+            obj.AddMember("minFilter", static_cast<unsigned int>(b.minFilter), w.mAl);
         }
     }
 
@@ -444,11 +493,6 @@ namespace glTF2 {
 
     }
 
-    inline void Write(Value& obj, Technique& b, AssetWriter& w)
-    {
-
-    }
-
     inline void Write(Value& obj, Texture& tex, AssetWriter& w)
     {
         if (tex.source) {
@@ -459,11 +503,6 @@ namespace glTF2 {
         }
     }
 
-    inline void Write(Value& obj, Light& b, AssetWriter& w)
-    {
-
-    }
-
 
     inline AssetWriter::AssetWriter(Asset& a)
         : mDoc()
@@ -523,88 +562,12 @@ namespace glTF2 {
         }
     }
 
-    inline void AssetWriter::WriteGLBFile(const char* path)
-    {
-        std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
-
-        if (outfile == 0) {
-            throw DeadlyExportError("Could not open output file: " + std::string(path));
-        }
-
-        // we will write the header later, skip its size
-        outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
-
-        StringBuffer docBuffer;
-        Writer<StringBuffer> writer(docBuffer);
-        mDoc.Accept(writer);
-
-        if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
-            throw DeadlyExportError("Failed to write scene data!");
-        }
-
-        WriteBinaryData(outfile.get(), docBuffer.GetSize());
-    }
-
-    inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
-    {
-        //
-        // write the body data
-        //
-
-        size_t bodyLength = 0;
-        if (Ref<Buffer> b = mAsset.GetBodyBuffer()) {
-            bodyLength = b->byteLength;
-
-            if (bodyLength > 0) {
-                size_t bodyOffset = sizeof(GLB_Header) + sceneLength;
-                bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4
-
-                outfile->Seek(bodyOffset, aiOrigin_SET);
-
-                if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
-                    throw DeadlyExportError("Failed to write body data!");
-                }
-            }
-        }
-
-        //
-        // write the header
-        //
-
-        GLB_Header header;
-        memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
-
-        header.version = 2;
-        AI_SWAP4(header.version);
-
-        header.length = uint32_t(sizeof(header) + sceneLength + bodyLength);
-        AI_SWAP4(header.length);
-
-        header.sceneLength = uint32_t(sceneLength);
-        AI_SWAP4(header.sceneLength);
-
-        header.sceneFormat = SceneFormat_JSON;
-        AI_SWAP4(header.sceneFormat);
-
-        outfile->Seek(0, aiOrigin_SET);
-
-        if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) {
-            throw DeadlyExportError("Failed to write the header!");
-        }
-    }
-
-
     inline void AssetWriter::WriteMetadata()
     {
         Value asset;
         asset.SetObject();
-        {
-            char versionChar[10];
-            ai_snprintf(versionChar, sizeof(versionChar), "%.1f", mAsset.asset.version);
-            asset.AddMember("version", Value(versionChar, mAl).Move(), mAl);
-
-            asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
-        }
+        asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
+        asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
         mDoc.AddMember("asset", asset, mAl);
     }
 
@@ -613,11 +576,10 @@ namespace glTF2 {
         Value exts;
         exts.SetArray();
         {
-            if (false)
-                exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
-
-            // This is used to export common materials with GLTF 2.
-            exts.PushBack(StringRef("KHR_materials_common"), mAl);
+            // This is used to export pbrSpecularGlossiness materials with GLTF 2.
+            if (this->mAsset.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
+                exts.PushBack(StringRef("KHR_materials_pbrSpecularGlossiness"), mAl);
+            }
         }
 
         if (!exts.Empty())

+ 200 - 231
code/glTF2Exporter.cpp

@@ -62,11 +62,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "glTF2AssetWriter.h"
 
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-	// Header files, Open3DGC.
-#	include <Open3DGC/o3dgcSC3DMCEncoder.h>
-#endif
-
 using namespace rapidjson;
 
 using namespace Assimp;
@@ -106,16 +101,8 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai
 
     mAsset.reset( new Asset( pIOSystem ) );
 
-    if (isBinary) {
-        mAsset->SetAsBinary();
-    }
-
     ExportMetadata();
 
-    //for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {}
-
-    //for (unsigned int i = 0; i < pScene->mNumLights; ++i) {}
-
     ExportMaterials();
 
     if (mScene->mRootNode) {
@@ -124,19 +111,13 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai
 
     ExportMeshes();
 
-    //for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
-
     ExportScene();
 
     ExportAnimations();
 
     AssetWriter writer(*mAsset);
 
-    if (isBinary) {
-        writer.WriteGLBFile(filename);
-    } else {
-        writer.WriteFile(filename);
-    }
+    writer.WriteFile(filename);
 }
 
 /*
@@ -234,63 +215,86 @@ inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& bu
     return acc;
 }
 
-namespace {
-    void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) {
-        if (mat->Get(propName, type, idx, val) == AI_SUCCESS) {}
-    }
-}
-
-void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref<Texture> texture)
+inline void SetSamplerWrap(SamplerWrap& wrap, aiTextureMapMode map)
 {
-    std::string samplerId = mAsset->FindUniqueID("", "sampler");
-    texture->sampler = mAsset->samplers.Create(samplerId);
-
-    aiTextureMapMode mapU, mapV;
-    aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU);
-    aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV);
-
-    switch (mapU) {
-        case aiTextureMapMode_Wrap:
-            texture->sampler->wrapS = SamplerWrap_Repeat;
-            break;
+    switch (map) {
         case aiTextureMapMode_Clamp:
-            texture->sampler->wrapS = SamplerWrap_Clamp_To_Edge;
+            wrap = SamplerWrap::Clamp_To_Edge;
             break;
         case aiTextureMapMode_Mirror:
-            texture->sampler->wrapS = SamplerWrap_Mirrored_Repeat;
+            wrap = SamplerWrap::Mirrored_Repeat;
             break;
-        case aiTextureMapMode_Decal:
-        default:
-            texture->sampler->wrapS = SamplerWrap_Repeat;
-            break;
-    };
-
-    switch (mapV) {
         case aiTextureMapMode_Wrap:
-            texture->sampler->wrapT = SamplerWrap_Repeat;
-            break;
-        case aiTextureMapMode_Clamp:
-            texture->sampler->wrapT = SamplerWrap_Clamp_To_Edge;
-            break;
-        case aiTextureMapMode_Mirror:
-            texture->sampler->wrapT = SamplerWrap_Mirrored_Repeat;
-            break;
         case aiTextureMapMode_Decal:
         default:
-            texture->sampler->wrapT = SamplerWrap_Repeat;
+            wrap = SamplerWrap::Repeat;
             break;
     };
+}
+
+void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref<Texture> texture, aiTextureType tt, unsigned int slot)
+{
+    aiString aId;
+    std::string id;
+    if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) {
+        id = aId.C_Str();
+    }
 
-    // Hard coded Texture filtering options because I do not know where to find them in the aiMaterial.
-    texture->sampler->magFilter = SamplerMagFilter_Linear;
-    texture->sampler->minFilter = SamplerMinFilter_Linear_Mipmap_Linear;
+    if (Ref<Sampler> ref = mAsset->samplers.Get(id.c_str())) {
+        texture->sampler = ref;
+    } else {
+        id = mAsset->FindUniqueID(id, "sampler");
+
+        texture->sampler = mAsset->samplers.Create(id.c_str());
+
+        aiTextureMapMode mapU, mapV;
+        SamplerMagFilter filterMag;
+        SamplerMinFilter filterMin;
+
+        if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) {
+            SetSamplerWrap(texture->sampler->wrapS, mapU);
+        }
+
+        if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) {
+            SetSamplerWrap(texture->sampler->wrapT, mapV);
+        }
+
+        if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) {
+            texture->sampler->magFilter = filterMag;
+        }
+
+        if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) {
+            texture->sampler->minFilter = filterMin;
+        }
+
+        aiString name;
+        if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) {
+            texture->sampler->name = name.C_Str();
+        }
+    }
 }
 
-void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTextureType tt)
+void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot)
 {
-    aiString tex;
+    std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName;
+
+    mat->Get(textureKey.c_str(), tt, slot, prop);
+}
+
+void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot)
+{
+    std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName;
+
+    mat->Get(textureKey.c_str(), tt, slot, prop);
+}
+
+void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTextureType tt, unsigned int slot = 0)
+{
+
     if (mat->GetTextureCount(tt) > 0) {
-        if (mat->Get(AI_MATKEY_TEXTURE(tt, 0), tex) == AI_SUCCESS) {
+        aiString tex;
+
+        if (mat->Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
             std::string path = tex.C_Str();
 
             if (path.size() > 0) {
@@ -325,22 +329,63 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
                         texture->source->uri = path;
                     }
 
-                    GetTexSampler(mat, texture);
+                    GetTexSampler(mat, texture, tt, slot);
                 }
             }
         }
     }
 }
 
-void glTF2Exporter::GetMatColorOrTex(const aiMaterial* mat, TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt)
+void glTF2Exporter::GetMatTex(const aiMaterial* mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
+{
+    Ref<Texture>& texture = prop.texture;
+
+    GetMatTex(mat, texture, tt, slot);
+
+    if (texture) {
+        GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
+    }
+}
+
+void glTF2Exporter::GetMatTex(const aiMaterial* mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
+{
+    Ref<Texture>& texture = prop.texture;
+
+    GetMatTex(mat, texture, tt, slot);
+
+    if (texture) {
+        GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
+        GetMatTexProp(mat, prop.scale, "scale", tt, slot);
+    }
+}
+
+void glTF2Exporter::GetMatTex(const aiMaterial* mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
+{
+    Ref<Texture>& texture = prop.texture;
+
+    GetMatTex(mat, texture, tt, slot);
+
+    if (texture) {
+        GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
+        GetMatTexProp(mat, prop.strength, "strength", tt, slot);
+    }
+}
+
+void glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const char* propName, int type, int idx)
 {
     aiColor4D col;
     if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
-        prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a;
+        prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[3] = col.a;
     }
-    GetMatTex(mat, prop.texture, tt);
 }
 
+void glTF2Exporter::GetMatColor(const aiMaterial* mat, vec3& prop, const char* propName, int type, int idx)
+{
+    aiColor3D col;
+    if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
+        prop[0] = col.r; prop[1] = col.g; prop[2] = col.b;
+    }
+}
 
 void glTF2Exporter::ExportMaterials()
 {
@@ -348,6 +393,9 @@ void glTF2Exporter::ExportMaterials()
     for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
         const aiMaterial* mat = mScene->mMaterials[i];
 
+        std::string id = "material_" + std::to_string(i);
+
+        Ref<Material> m = mAsset->materials.Create(id);
 
         std::string name;
         if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) {
@@ -355,17 +403,70 @@ void glTF2Exporter::ExportMaterials()
         }
         name = mAsset->FindUniqueID(name, "material");
 
-        Ref<Material> m = mAsset->materials.Create(name);
+        m->name = name;
+
+        GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_DIFFUSE);
+        GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
+        GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE);
+
+        if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) {
+            //if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
+            m->pbrMetallicRoughness.metallicFactor = 0;
+        }
+
+        mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor);
 
-        GetMatColorOrTex(mat, m->ambient, AI_MATKEY_COLOR_AMBIENT, aiTextureType_AMBIENT);
-        GetMatColorOrTex(mat, m->diffuse, AI_MATKEY_COLOR_DIFFUSE, aiTextureType_DIFFUSE);
-        GetMatColorOrTex(mat, m->specular, AI_MATKEY_COLOR_SPECULAR, aiTextureType_SPECULAR);
-        GetMatColorOrTex(mat, m->emission, AI_MATKEY_COLOR_EMISSIVE, aiTextureType_EMISSIVE);
-        GetMatTex(mat, m->normal, aiTextureType_NORMALS);
+        GetMatTex(mat, m->normalTexture, aiTextureType_NORMALS);
+        GetMatTex(mat, m->occlusionTexture, aiTextureType_LIGHTMAP);
+        GetMatTex(mat, m->emissiveTexture, aiTextureType_EMISSIVE);
+        GetMatColor(mat, m->emissiveFactor, AI_MATKEY_COLOR_EMISSIVE);
 
-        m->transparent = mat->Get(AI_MATKEY_OPACITY, m->transparency) == aiReturn_SUCCESS && m->transparency != 1.0;
+        mat->Get(AI_MATKEY_TWOSIDED, m->doubleSided);
+        mat->Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff);
 
-        GetMatScalar(mat, m->shininess, AI_MATKEY_SHININESS);
+        bool foundAlphaMode = false;
+        for (size_t i = 0; i < mat->mNumProperties; ++i) {
+            aiMaterialProperty *prop = mat->mProperties[i];
+            if (prop->mKey != aiString("$mat.gltf.alphaMode"))
+                continue;
+
+            std::string alphaMode;
+            for (size_t c = 0; c < prop->mDataLength; ++c)
+                alphaMode += prop->mData[c];
+            m->alphaMode = alphaMode;
+            foundAlphaMode = true;
+        }
+
+        if (!foundAlphaMode) {
+            float opacity;
+
+            if (mat->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) {
+                if (opacity < 1) {
+                    m->alphaMode = "MASK";
+                    m->pbrMetallicRoughness.baseColorFactor[3] *= opacity;
+                }
+            }
+        }
+
+        bool hasPbrSpecularGlossiness = false;
+        mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS, hasPbrSpecularGlossiness);
+
+        if (hasPbrSpecularGlossiness) {
+
+            if (!mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
+                mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
+            }
+
+            PbrSpecularGlossiness pbrSG;
+
+            GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR);
+            GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR);
+            mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR, pbrSG.glossinessFactor);
+            GetMatTex(mat, pbrSG.diffuseTexture, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE);
+            GetMatTex(mat, pbrSG.specularGlossinessTexture, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE);
+
+            m->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
+        }
     }
 }
 
@@ -375,16 +476,15 @@ void glTF2Exporter::ExportMaterials()
  */
 bool FindMeshNode(Ref<Node>& nodeIn, Ref<Node>& meshNode, std::string meshID)
 {
-    for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) {
-        if (meshID.compare(nodeIn->meshes[i]->id) == 0) {
-          meshNode = nodeIn;
-          return true;
-        }
+
+    if (nodeIn->mesh && meshID.compare(nodeIn->mesh->id) == 0) {
+        meshNode = nodeIn;
+        return true;
     }
 
     for (unsigned int i = 0; i < nodeIn->children.size(); ++i) {
         if(FindMeshNode(nodeIn->children[i], meshNode, meshID)) {
-          return true;
+            return true;
         }
     }
 
@@ -502,15 +602,6 @@ void glTF2Exporter::ExportMeshes()
     // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
     typedef unsigned short IndicesType;
 
-    // Variables needed for compression. BEGIN.
-    // Indices, not pointers - because pointer to buffer is changing while writing to it.
-    size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
-    size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
-    std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
-    size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
-    bool comp_allow;// Point that data of current mesh can be compressed.
-    // Variables needed for compression. END.
-
     std::string fname = std::string(mFilename);
     std::string bufferIdPrefix = fname.substr(0, fname.rfind(".gltf"));
     std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str());
@@ -543,48 +634,22 @@ void glTF2Exporter::ExportMeshes()
 	for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
 		const aiMesh* aim = mScene->mMeshes[idx_mesh];
 
-		// Check if compressing requested and mesh can be encoded.
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-		comp_allow = mProperties->GetPropertyBool("extensions.Open3DGC.use", false);
-#else
-		comp_allow = false;
-#endif
-
-		if(comp_allow && (aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0) && (aim->mNumFaces > 0))
-		{
-			idx_srcdata_tc.clear();
-			idx_srcdata_tc.reserve(AI_MAX_NUMBER_OF_TEXTURECOORDS);
-		}
-		else
-		{
-			std::string msg;
-
-			if(aim->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
-				msg = "all primitives of the mesh must be a triangles.";
-			else
-				msg = "mesh must has vertices and faces.";
+        std::string name = aim->mName.C_Str();
 
-			DefaultLogger::get()->warn("GLTF: can not use Open3DGC-compression: " + msg);
-            comp_allow = false;
-		}
-
-        std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
+        std::string meshId = mAsset->FindUniqueID(name, "mesh");
         Ref<Mesh> m = mAsset->meshes.Create(meshId);
         m->primitives.resize(1);
         Mesh::Primitive& p = m->primitives.back();
 
+        m->name = name;
+
         p.material = mAsset->materials.Get(aim->mMaterialIndex);
 
 		/******************* Vertices ********************/
-		// If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored.
-		if(comp_allow) idx_srcdata_begin = b->byteLength;
-
         Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
 		if (v) p.attributes.position.push_back(v);
 
 		/******************** Normals ********************/
-		if(comp_allow && (aim->mNormals != 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array.
-
 		Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
 		if (n) p.attributes.normal.push_back(n);
 
@@ -600,16 +665,12 @@ void glTF2Exporter::ExportMeshes()
             if (aim->mNumUVComponents[i] > 0) {
                 AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
 
-				if(comp_allow) idx_srcdata_tc.push_back(b->byteLength);// Store index of texture coordinates array.
-
 				Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, false);
 				if (tc) p.attributes.texcoord.push_back(tc);
 			}
 		}
 
 		/*************** Vertices indices ****************/
-		idx_srcdata_ind = b->byteLength;// Store index of indices array.
-
 		if (aim->mNumFaces > 0) {
 			std::vector<IndicesType> indices;
 			unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
@@ -634,103 +695,11 @@ void glTF2Exporter::ExportMeshes()
                 p.mode = PrimitiveMode_TRIANGLES;
         }
 
-    /*************** Skins ****************/
-    if(aim->HasBones()) {
-        ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
-    }
-
-		/****************** Compression ******************/
-		///TODO: animation: weights, joints.
-		if(comp_allow)
-		{
-#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
-			// Only one type of compression supported at now - Open3DGC.
-			//
-			o3dgc::BinaryStream bs;
-			o3dgc::SC3DMCEncoder<IndicesType> encoder;
-			o3dgc::IndexedFaceSet<IndicesType> comp_o3dgc_ifs;
-			o3dgc::SC3DMCEncodeParams comp_o3dgc_params;
-
-			//
-			// Fill data for encoder.
-			//
-			// Quantization
-			unsigned quant_coord = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.POSITION", 12);
-			unsigned quant_normal = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.NORMAL", 10);
-			unsigned quant_texcoord = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.TEXCOORD", 10);
-
-			// Prediction
-			o3dgc::O3DGCSC3DMCPredictionMode prediction_position = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
-			o3dgc::O3DGCSC3DMCPredictionMode prediction_normal =  o3dgc::O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;
-			o3dgc::O3DGCSC3DMCPredictionMode prediction_texcoord = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
-
-			// IndexedFacesSet: "Crease angle", "solid", "convex" are set to default.
-			comp_o3dgc_ifs.SetCCW(true);
-			comp_o3dgc_ifs.SetIsTriangularMesh(true);
-			comp_o3dgc_ifs.SetNumFloatAttributes(0);
-			// Coordinates
-			comp_o3dgc_params.SetCoordQuantBits(quant_coord);
-			comp_o3dgc_params.SetCoordPredMode(prediction_position);
-			comp_o3dgc_ifs.SetNCoord(aim->mNumVertices);
-			comp_o3dgc_ifs.SetCoord((o3dgc::Real* const)&b->GetPointer()[idx_srcdata_begin]);
-			// Normals
-			if(idx_srcdata_normal != SIZE_MAX)
-			{
-				comp_o3dgc_params.SetNormalQuantBits(quant_normal);
-				comp_o3dgc_params.SetNormalPredMode(prediction_normal);
-				comp_o3dgc_ifs.SetNNormal(aim->mNumVertices);
-				comp_o3dgc_ifs.SetNormal((o3dgc::Real* const)&b->GetPointer()[idx_srcdata_normal]);
-			}
-
-			// Texture coordinates
-			for(size_t num_tc = 0; num_tc < idx_srcdata_tc.size(); num_tc++)
-			{
-				size_t num = comp_o3dgc_ifs.GetNumFloatAttributes();
-
-				comp_o3dgc_params.SetFloatAttributeQuantBits(static_cast<unsigned long>(num), quant_texcoord);
-				comp_o3dgc_params.SetFloatAttributePredMode(static_cast<unsigned long>(num), prediction_texcoord);
-				comp_o3dgc_ifs.SetNFloatAttribute(static_cast<unsigned long>(num), aim->mNumVertices);// number of elements.
-				comp_o3dgc_ifs.SetFloatAttributeDim(static_cast<unsigned long>(num), aim->mNumUVComponents[num_tc]);// components per element: aiVector3D => x * float
-				comp_o3dgc_ifs.SetFloatAttributeType(static_cast<unsigned long>(num), o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD);
-				comp_o3dgc_ifs.SetFloatAttribute(static_cast<unsigned long>(num), (o3dgc::Real* const)&b->GetPointer()[idx_srcdata_tc[num_tc]]);
-				comp_o3dgc_ifs.SetNumFloatAttributes(static_cast<unsigned long>(num + 1));
-			}
-
-			// Coordinates indices
-			comp_o3dgc_ifs.SetNCoordIndex(aim->mNumFaces);
-			comp_o3dgc_ifs.SetCoordIndex((IndicesType* const)&b->GetPointer()[idx_srcdata_ind]);
-			// Prepare to enconding
-			comp_o3dgc_params.SetNumFloatAttributes(comp_o3dgc_ifs.GetNumFloatAttributes());
-			if(mProperties->GetPropertyBool("extensions.Open3DGC.binary", true))
-				comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_BINARY);
-			else
-				comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_ASCII);
-
-			comp_o3dgc_ifs.ComputeMinMax(o3dgc::O3DGC_SC3DMC_MAX_ALL_DIMS);
-			//
-			// Encoding
-			//
-			encoder.Encode(comp_o3dgc_params, comp_o3dgc_ifs, bs);
-			// Replace data in buffer.
-			b->ReplaceData(idx_srcdata_begin, b->byteLength - idx_srcdata_begin, bs.GetBuffer(), bs.GetSize());
-			//
-			// Add information about extension to mesh.
-			//
-			// Create extension structure.
-			Mesh::SCompression_Open3DGC* ext = new Mesh::SCompression_Open3DGC;
-
-			// Fill it.
-			ext->Buffer = b->id;
-			ext->Offset = idx_srcdata_begin;
-			ext->Count = b->byteLength - idx_srcdata_begin;
-			ext->Binary = mProperties->GetPropertyBool("extensions.Open3DGC.binary");
-			ext->IndicesCount = comp_o3dgc_ifs.GetNCoordIndex() * 3;
-			ext->VerticesCount = comp_o3dgc_ifs.GetNCoord();
-			// And assign to mesh.
-			m->Extension.push_back(ext);
-#endif
-		}// if(comp_allow)
-	}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i)
+        /*************** Skins ****************/
+        if(aim->HasBones()) {
+            ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
+        }
+    }
 
     //----------------------------------------
     // Finish the skin
@@ -786,8 +755,8 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n)
         CopyValue(n->mTransformation, node->matrix.value);
     }
 
-    for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
-        node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
+    if (n->mNumMeshes > 0) {
+        node->mesh = mAsset->meshes.Get(n->mMeshes[0]);
     }
 
     for (unsigned int i = 0; i < n->mNumChildren; ++i) {
@@ -815,8 +784,8 @@ unsigned int glTF2Exporter::ExportNode(const aiNode* n, Ref<Node>& parent)
         CopyValue(n->mTransformation, node->matrix.value);
     }
 
-    for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
-        node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
+    if (n->mNumMeshes > 0) {
+        node->mesh = mAsset->meshes.Get(n->mMeshes[0]);
     }
 
     for (unsigned int i = 0; i < n->mNumChildren; ++i) {
@@ -845,7 +814,7 @@ void glTF2Exporter::ExportScene()
 void glTF2Exporter::ExportMetadata()
 {
     AssetMetadata& asset = mAsset->asset;
-    asset.version = 2;
+    asset.version = "2.0";
 
     char buffer[256];
     ai_snprintf(buffer, 256, "Open Asset Import Library (assimp v%d.%d.%d)",
@@ -886,7 +855,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             timeData[i] = nodeChannel->mPositionKeys[frameIndex].mTime / ticksPerSecond;
         }
 
-        Ref<Accessor> timeAccessor = ExportData(mAsset, animId, buffer, numKeyframes, &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT);
+        Ref<Accessor> timeAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT);
         if (timeAccessor) animRef->Parameters.TIME = timeAccessor;
     }
 
@@ -899,7 +868,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             translationData[i] = nodeChannel->mPositionKeys[frameIndex].mValue;
         }
 
-        Ref<Accessor> tranAccessor = ExportData(mAsset, animId, buffer, numKeyframes, translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+        Ref<Accessor> tranAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
         if ( tranAccessor ) {
             animRef->Parameters.translation = tranAccessor;
         }
@@ -915,7 +884,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             scaleData[i] = nodeChannel->mScalingKeys[frameIndex].mValue;
         }
 
-        Ref<Accessor> scaleAccessor = ExportData(mAsset, animId, buffer, numKeyframes, scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+        Ref<Accessor> scaleAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
         if ( scaleAccessor ) {
             animRef->Parameters.scale = scaleAccessor;
         }
@@ -934,7 +903,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             rotationData[i][3] = nodeChannel->mRotationKeys[frameIndex].mValue.w;
         }
 
-        Ref<Accessor> rotAccessor = ExportData(mAsset, animId, buffer, numKeyframes, rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
+        Ref<Accessor> rotAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
         if ( rotAccessor ) {
             animRef->Parameters.rotation = rotAccessor;
         }
@@ -963,7 +932,7 @@ void glTF2Exporter::ExportAnimations()
             name = mAsset->FindUniqueID(name, "animation");
             Ref<Animation> animRef = mAsset->animations.Create(name);
 
-            /******************* Parameters ********************/
+            // Parameters
             ExtractAnimationData(*mAsset, name, animRef, bufferRef, nodeChannel, anim->mTicksPerSecond);
 
             for (unsigned int j = 0; j < 3; ++j) {
@@ -989,7 +958,7 @@ void glTF2Exporter::ExportAnimations()
                 Animation::AnimChannel tmpAnimChannel;
                 Animation::AnimSampler tmpAnimSampler;
 
-                tmpAnimChannel.sampler = animRef->Samplers.size();
+                tmpAnimChannel.sampler = static_cast<int>(animRef->Samplers.size());
                 tmpAnimChannel.target.path = channelType;
                 tmpAnimSampler.output = channelType;
                 tmpAnimSampler.id = name + "_" + channelType;

+ 16 - 3
code/glTF2Exporter.h

@@ -66,8 +66,15 @@ namespace glTF2
 
     class Asset;
     struct TexProperty;
+    struct TextureInfo;
+    struct NormalTextureInfo;
+    struct OcclusionTextureInfo;
     struct Node;
     struct Texture;
+
+    // Vec/matrix types, as raw float arrays
+    typedef float (vec3)[3];
+    typedef float (vec4)[4];
 }
 
 namespace Assimp
@@ -101,9 +108,15 @@ namespace Assimp
 
         void WriteBinaryData(IOStream* outfile, std::size_t sceneLength);
 
-        void GetTexSampler(const aiMaterial* mat, glTF2::Ref<glTF2::Texture> texture);
-        void GetMatTex(const aiMaterial* mat, glTF2::Ref<glTF2::Texture>& texture, aiTextureType tt);
-        void GetMatColorOrTex(const aiMaterial* mat, glTF2::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt);
+        void GetTexSampler(const aiMaterial* mat, glTF2::Ref<glTF2::Texture> texture, aiTextureType tt, unsigned int slot);
+        void GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx);
+        void GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx);
+        void GetMatTex(const aiMaterial* mat, glTF2::Ref<glTF2::Texture>& texture, aiTextureType tt, unsigned int slot);
+        void GetMatTex(const aiMaterial* mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot);
+        void GetMatTex(const aiMaterial* mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot);
+        void GetMatTex(const aiMaterial* mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot);
+        void GetMatColor(const aiMaterial* mat, glTF2::vec4& prop, const char* propName, int type, int idx);
+        void GetMatColor(const aiMaterial* mat, glTF2::vec3& prop, const char* propName, int type, int idx);
         void ExportMetadata();
         void ExportMaterials();
         void ExportMeshes();

+ 654 - 0
code/glTF2Importer.cpp

@@ -0,0 +1,654 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
+
+#include "glTF2Importer.h"
+#include "StringComparison.h"
+#include "StringUtils.h"
+
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <assimp/ai_assert.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/importerdesc.h>
+
+#include <memory>
+
+#include "MakeVerboseFormat.h"
+
+#include "glTF2Asset.h"
+// This is included here so WriteLazyDict<T>'s definition is found.
+#include "glTF2AssetWriter.h"
+#include <rapidjson/document.h>
+#include <rapidjson/rapidjson.h>
+
+using namespace Assimp;
+using namespace glTF2;
+
+
+//
+// glTF2Importer
+//
+
+static const aiImporterDesc desc = {
+    "glTF2 Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
+    0,
+    0,
+    0,
+    0,
+    "gltf glb"
+};
+
+glTF2Importer::glTF2Importer()
+: BaseImporter()
+, meshOffsets()
+, embeddedTexIdxs()
+, mScene( NULL ) {
+    // empty
+}
+
+glTF2Importer::~glTF2Importer() {
+    // empty
+}
+
+const aiImporterDesc* glTF2Importer::GetInfo() const
+{
+    return &desc;
+}
+
+bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+{
+    const std::string &extension = GetExtension(pFile);
+
+    if (extension != "gltf") // We currently can't read glTF2 binary files (.glb), yet
+        return false;
+
+    if (checkSig && pIOHandler) {
+        glTF2::Asset asset(pIOHandler);
+        try {
+            asset.Load(pFile);
+            std::string version = asset.asset.version;
+            return !version.empty() && version[0] == '2';
+        } catch (...) {
+            return false;
+        }
+    }
+
+    return false;
+}
+
+
+//static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
+//{
+//    out.r = v[0]; out.g = v[1]; out.b = v[2];
+//}
+
+static void CopyValue(const glTF2::vec4& v, aiColor4D& out)
+{
+    out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3];
+}
+
+/*static void CopyValue(const glTF2::vec4& v, aiColor3D& out)
+{
+    out.r = v[0]; out.g = v[1]; out.b = v[2];
+}*/
+
+static void CopyValue(const glTF2::vec3& v, aiColor4D& out)
+{
+    out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = 1.0;
+}
+
+static void CopyValue(const glTF2::vec3& v, aiVector3D& out)
+{
+    out.x = v[0]; out.y = v[1]; out.z = v[2];
+}
+
+static void CopyValue(const glTF2::vec4& v, aiQuaternion& out)
+{
+    out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3];
+}
+
+static void CopyValue(const glTF2::mat4& v, aiMatrix4x4& o)
+{
+    o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3];
+    o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7];
+    o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11];
+    o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
+}
+
+inline void SetMaterialColorProperty(Asset& r, vec4& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx)
+{
+    aiColor4D col;
+    CopyValue(prop, col);
+    mat->AddProperty(&col, 1, pKey, type, idx);
+}
+
+inline void SetMaterialColorProperty(Asset& r, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx)
+{
+    aiColor4D col;
+    CopyValue(prop, col);
+    mat->AddProperty(&col, 1, pKey, type, idx);
+}
+
+inline void SetMaterialTextureProperty(std::vector<int>& embeddedTexIdxs, Asset& r, glTF2::TextureInfo prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0)
+{
+    if (prop.texture && prop.texture->source) {
+        aiString uri(prop.texture->source->uri);
+
+        int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
+        if (texIdx != -1) { // embedded
+            // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
+            uri.data[0] = '*';
+            uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
+        }
+
+        mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot));
+        mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot);
+
+        if (prop.texture->sampler) {
+            Ref<Sampler> sampler = prop.texture->sampler;
+
+            aiString name(sampler->name);
+            aiString id(sampler->id);
+
+            mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot));
+            mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot));
+
+            mat->AddProperty(&sampler->wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
+            mat->AddProperty(&sampler->wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
+
+            if (sampler->magFilter != SamplerMagFilter::UNSET) {
+                mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot));
+            }
+
+            if (sampler->minFilter != SamplerMinFilter::UNSET) {
+                mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot));
+            }
+        }
+    }
+}
+
+void glTF2Importer::ImportMaterials(glTF2::Asset& r)
+{
+    mScene->mNumMaterials = unsigned(r.materials.Size());
+    mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
+
+    for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
+        aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial();
+
+        Material& mat = r.materials[i];
+
+        if (!mat.name.empty()) {
+            aiString str(mat.name);
+
+            aimat->AddProperty(&str, AI_MATKEY_NAME);
+        }
+
+        SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
+        SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE);
+        SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
+        aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR);
+        aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR);
+
+        SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS);
+        SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP);
+        SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE);
+        SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE);
+
+        aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
+        aimat->AddProperty(&mat.alphaMode, 1, AI_MATKEY_GLTF_ALPHAMODE);
+        aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
+
+        //pbrSpecularGlossiness
+        if (mat.pbrSpecularGlossiness.isPresent) {
+            PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
+
+            aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS);
+            SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR);
+            SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR);
+            aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR);
+            SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE);
+            SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE);
+        }
+    }
+}
+
+
+static inline void SetFace(aiFace& face, int a)
+{
+    face.mNumIndices = 1;
+    face.mIndices = new unsigned int[1];
+    face.mIndices[0] = a;
+}
+
+static inline void SetFace(aiFace& face, int a, int b)
+{
+    face.mNumIndices = 2;
+    face.mIndices = new unsigned int[2];
+    face.mIndices[0] = a;
+    face.mIndices[1] = b;
+}
+
+static inline void SetFace(aiFace& face, int a, int b, int c)
+{
+    face.mNumIndices = 3;
+    face.mIndices = new unsigned int[3];
+    face.mIndices[0] = a;
+    face.mIndices[1] = b;
+    face.mIndices[2] = c;
+}
+
+static inline bool CheckValidFacesIndices(aiFace* faces, unsigned nFaces, unsigned nVerts)
+{
+    for (unsigned i = 0; i < nFaces; ++i) {
+        for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
+            unsigned idx = faces[i].mIndices[j];
+            if (idx >= nVerts)
+                return false;
+        }
+    }
+    return true;
+}
+
+void glTF2Importer::ImportMeshes(glTF2::Asset& r)
+{
+    std::vector<aiMesh*> meshes;
+
+    unsigned int k = 0;
+
+    for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
+        Mesh& mesh = r.meshes[m];
+
+        meshOffsets.push_back(k);
+        k += unsigned(mesh.primitives.size());
+
+        for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
+            Mesh::Primitive& prim = mesh.primitives[p];
+
+            aiMesh* aim = new aiMesh();
+            meshes.push_back(aim);
+
+            aim->mName = mesh.name.empty() ? mesh.id : mesh.name;
+
+            if (mesh.primitives.size() > 1) {
+                size_t& len = aim->mName.length;
+                aim->mName.data[len] = '-';
+                len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
+            }
+
+            switch (prim.mode) {
+                case PrimitiveMode_POINTS:
+                    aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
+                    break;
+
+                case PrimitiveMode_LINES:
+                case PrimitiveMode_LINE_LOOP:
+                case PrimitiveMode_LINE_STRIP:
+                    aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
+                    break;
+
+                case PrimitiveMode_TRIANGLES:
+                case PrimitiveMode_TRIANGLE_STRIP:
+                case PrimitiveMode_TRIANGLE_FAN:
+                    aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+                    break;
+
+            }
+
+            Mesh::Primitive::Attributes& attr = prim.attributes;
+
+            if (attr.position.size() > 0 && attr.position[0]) {
+                aim->mNumVertices = attr.position[0]->count;
+                attr.position[0]->ExtractData(aim->mVertices);
+            }
+
+            if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals);
+
+            for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
+                attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
+                aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
+
+                aiVector3D* values = aim->mTextureCoords[tc];
+                for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
+                    values[i].y = 1 - values[i].y; // Flip Y coords
+                }
+            }
+
+
+            if (prim.indices) {
+                aiFace* faces = 0;
+                unsigned int nFaces = 0;
+
+                unsigned int count = prim.indices->count;
+
+                Accessor::Indexer data = prim.indices->GetIndexer();
+                ai_assert(data.IsValid());
+
+                switch (prim.mode) {
+                    case PrimitiveMode_POINTS: {
+                        nFaces = count;
+                        faces = new aiFace[nFaces];
+                        for (unsigned int i = 0; i < count; ++i) {
+                            SetFace(faces[i], data.GetUInt(i));
+                        }
+                        break;
+                    }
+
+                    case PrimitiveMode_LINES: {
+                        nFaces = count / 2;
+                        faces = new aiFace[nFaces];
+                        for (unsigned int i = 0; i < count; i += 2) {
+                            SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
+                        }
+                        break;
+                    }
+
+                    case PrimitiveMode_LINE_LOOP:
+                    case PrimitiveMode_LINE_STRIP: {
+                        nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
+                        faces = new aiFace[nFaces];
+                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
+                        for (unsigned int i = 2; i < count; ++i) {
+                            SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
+                        }
+                        if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
+                            SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
+                        }
+                        break;
+                    }
+
+                    case PrimitiveMode_TRIANGLES: {
+                        nFaces = count / 3;
+                        faces = new aiFace[nFaces];
+                        for (unsigned int i = 0; i < count; i += 3) {
+                            SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
+                        }
+                        break;
+                    }
+                    case PrimitiveMode_TRIANGLE_STRIP: {
+                        nFaces = count - 2;
+                        faces = new aiFace[nFaces];
+                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
+                        for (unsigned int i = 3; i < count; ++i) {
+                            SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
+                        }
+                        break;
+                    }
+                    case PrimitiveMode_TRIANGLE_FAN:
+                        nFaces = count - 2;
+                        faces = new aiFace[nFaces];
+                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
+                        for (unsigned int i = 3; i < count; ++i) {
+                            SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
+                        }
+                        break;
+                }
+
+                if (faces) {
+                    aim->mFaces = faces;
+                    aim->mNumFaces = nFaces;
+                    ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
+                }
+            }
+
+
+            if (prim.material) {
+                aim->mMaterialIndex = prim.material.GetIndex();
+            }
+        }
+    }
+
+    meshOffsets.push_back(k);
+
+    CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
+}
+
+void glTF2Importer::ImportCameras(glTF2::Asset& r)
+{
+    if (!r.cameras.Size()) return;
+
+    mScene->mNumCameras = r.cameras.Size();
+    mScene->mCameras = new aiCamera*[r.cameras.Size()];
+
+    for (size_t i = 0; i < r.cameras.Size(); ++i) {
+        Camera& cam = r.cameras[i];
+
+        aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
+
+        if (cam.type == Camera::Perspective) {
+
+            aicam->mAspect        = cam.cameraProperties.perspective.aspectRatio;
+            aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * aicam->mAspect;
+            aicam->mClipPlaneFar  = cam.cameraProperties.perspective.zfar;
+            aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear;
+        }
+        else {
+            // assimp does not support orthographic cameras
+        }
+    }
+}
+
+aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>& meshOffsets, glTF2::Ref<glTF2::Node>& ptr)
+{
+    Node& node = *ptr;
+
+    aiNode* ainode = new aiNode(node.id);
+
+    if (!node.children.empty()) {
+        ainode->mNumChildren = unsigned(node.children.size());
+        ainode->mChildren = new aiNode*[ainode->mNumChildren];
+
+        for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
+            aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
+            child->mParent = ainode;
+            ainode->mChildren[i] = child;
+        }
+    }
+
+    aiMatrix4x4& matrix = ainode->mTransformation;
+    if (node.matrix.isPresent) {
+        CopyValue(node.matrix.value, matrix);
+    }
+    else {
+        if (node.translation.isPresent) {
+            aiVector3D trans;
+            CopyValue(node.translation.value, trans);
+            aiMatrix4x4 t;
+            aiMatrix4x4::Translation(trans, t);
+            matrix = t * matrix;
+        }
+
+        if (node.scale.isPresent) {
+            aiVector3D scal(1.f);
+            CopyValue(node.scale.value, scal);
+            aiMatrix4x4 s;
+            aiMatrix4x4::Scaling(scal, s);
+            matrix = s * matrix;
+        }
+
+
+        if (node.rotation.isPresent) {
+            aiQuaternion rot;
+            CopyValue(node.rotation.value, rot);
+            matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
+        }
+    }
+
+    if (node.mesh) {
+
+        int idx = node.mesh.GetIndex();
+
+        ai_assert(idx >= 0 && idx < meshOffsets.size());
+
+        unsigned int offBegin = meshOffsets[idx];
+        unsigned int offEnd = meshOffsets[idx + 1];
+        int k = 0;
+        
+        ai_assert(offEnd >= offBegin);
+
+        ainode->mNumMeshes = offEnd - offBegin;
+        ainode->mMeshes = new unsigned int[ainode->mNumMeshes];
+
+        for (unsigned int j = offBegin; j < offEnd; ++j, ++k) {
+            ai_assert(k < ainode->mNumMeshes);
+            ainode->mMeshes[k] = j;
+        }
+    }
+
+    if (node.camera) {
+        pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
+    }
+
+    return ainode;
+}
+
+void glTF2Importer::ImportNodes(glTF2::Asset& r)
+{
+    if (!r.scene) return;
+
+    std::vector< Ref<Node> > rootNodes = r.scene->nodes;
+
+    // The root nodes
+    unsigned int numRootNodes = unsigned(rootNodes.size());
+    if (numRootNodes == 1) { // a single root node: use it
+        mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
+    }
+    else if (numRootNodes > 1) { // more than one root node: create a fake root
+        aiNode* root = new aiNode("ROOT");
+        root->mChildren = new aiNode*[numRootNodes];
+        for (unsigned int i = 0; i < numRootNodes; ++i) {
+            aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
+            node->mParent = root;
+            root->mChildren[root->mNumChildren++] = node;
+        }
+        mScene->mRootNode = root;
+    }
+
+    //if (!mScene->mRootNode) {
+    //  mScene->mRootNode = new aiNode("EMPTY");
+    //}
+}
+
+void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset& r)
+{
+    embeddedTexIdxs.resize(r.images.Size(), -1);
+
+    int numEmbeddedTexs = 0;
+    for (size_t i = 0; i < r.images.Size(); ++i) {
+        if (r.images[i].HasData())
+            numEmbeddedTexs += 1;
+    }
+
+    if (numEmbeddedTexs == 0)
+        return;
+
+    mScene->mTextures = new aiTexture*[numEmbeddedTexs];
+
+    // Add the embedded textures
+    for (size_t i = 0; i < r.images.Size(); ++i) {
+        Image img = r.images[i];
+        if (!img.HasData()) continue;
+
+        int idx = mScene->mNumTextures++;
+        embeddedTexIdxs[i] = idx;
+
+        aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
+
+        size_t length = img.GetDataLength();
+        void* data = img.StealData();
+
+        tex->mWidth = static_cast<unsigned int>(length);
+        tex->mHeight = 0;
+        tex->pcData = reinterpret_cast<aiTexel*>(data);
+
+        if (!img.mimeType.empty()) {
+            const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
+            if (ext) {
+                if (strcmp(ext, "jpeg") == 0) ext = "jpg";
+
+                size_t len = strlen(ext);
+                if (len <= 3) {
+                    strcpy(tex->achFormatHint, ext);
+                }
+            }
+        }
+    }
+}
+
+void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
+
+    this->mScene = pScene;
+
+    // read the asset file
+    glTF2::Asset asset(pIOHandler);
+    asset.Load(pFile);
+
+    //
+    // Copy the data out
+    //
+
+    ImportEmbeddedTextures(asset);
+    ImportMaterials(asset);
+
+    ImportMeshes(asset);
+
+    ImportCameras(asset);
+
+    ImportNodes(asset);
+
+    // TODO: it does not split the loaded vertices, should it?
+    //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
+    MakeVerboseFormatProcess process;
+    process.Execute(pScene);
+
+
+    if (pScene->mNumMeshes == 0) {
+        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+    }
+}
+
+#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
+

+ 91 - 0
code/glTF2Importer.h

@@ -0,0 +1,91 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_GLTF2IMPORTER_H_INC
+#define AI_GLTF2IMPORTER_H_INC
+
+#include "BaseImporter.h"
+#include <assimp/DefaultIOSystem.h>
+
+struct aiNode;
+
+
+namespace glTF2
+{
+    class Asset;
+}
+
+namespace Assimp {
+
+/**
+ * Load the glTF2 format.
+ * https://github.com/KhronosGroup/glTF/tree/master/specification
+ */
+class glTF2Importer : public BaseImporter{
+public:
+    glTF2Importer();
+    virtual ~glTF2Importer();
+    virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const;
+
+protected:
+    virtual const aiImporterDesc* GetInfo() const;
+    virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler );
+
+private:
+
+    std::vector<unsigned int> meshOffsets;
+
+    std::vector<int> embeddedTexIdxs;
+
+    aiScene* mScene;
+
+    void ImportEmbeddedTextures(glTF2::Asset& a);
+    void ImportMaterials(glTF2::Asset& a);
+    void ImportMeshes(glTF2::Asset& a);
+    void ImportCameras(glTF2::Asset& a);
+    void ImportLights(glTF2::Asset& a);
+    void ImportNodes(glTF2::Asset& a);
+
+};
+
+} // Namespace assimp
+
+#endif // AI_GLTF2IMPORTER_H_INC
+

+ 2 - 2
code/glTFAsset.h

@@ -1058,13 +1058,13 @@ namespace glTF
             std::string version; //!< Specifies the target rendering API (default: "1.0.3")
         } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
 
-        float version; //!< The glTF format version (should be 1.0)
+        std::string version; //!< The glTF format version (should be 1.0)
 
         void Read(Document& doc);
 
         AssetMetadata()
             : premultipliedAlpha(false)
-            , version(0)
+            , version("")
         {
         }
     };

+ 23 - 14
code/glTFAsset.inl

@@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "StringUtils.h"
+#include <iomanip>
 
 // Header files, Assimp
 #include <assimp/DefaultLogger.hpp>
@@ -128,6 +129,12 @@ namespace {
         return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
     }
 
+    inline Value* FindNumber(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0;
+    }
+
     inline Value* FindArray(Value& val, const char* id)
     {
         Value::MemberIterator it = val.FindMember(id);
@@ -309,7 +316,9 @@ inline void Buffer::Read(Value& obj, Asset& r)
     }
     else { // Local file
         if (byteLength > 0) {
-            IOStream* file = r.OpenFile(uri, "rb");
+            std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : "";
+
+            IOStream* file = r.OpenFile(dir + uri, "rb");
             if (file) {
                 bool ok = LoadFromStream(*file, byteLength);
                 delete file;
@@ -1228,13 +1237,21 @@ inline void Scene::Read(Value& obj, Asset& r)
 inline void AssetMetadata::Read(Document& doc)
 {
     // read the version, etc.
-    float statedVersion = 0;
     if (Value* obj = FindObject(doc, "asset")) {
         ReadMember(*obj, "copyright", copyright);
         ReadMember(*obj, "generator", generator);
 
         premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
-        statedVersion = MemberOrDefault(*obj, "version", 0);
+
+        if (Value* versionString = FindString(*obj, "version")) {
+            version = versionString->GetString();
+        } else if (Value* versionNumber = FindNumber (*obj, "version")) {
+            char buf[4];
+
+            ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
+
+            version = buf;
+        }
 
         if (Value* profile = FindObject(*obj, "profile")) {
             ReadMember(*profile, "api",     this->profile.api);
@@ -1242,16 +1259,8 @@ inline void AssetMetadata::Read(Document& doc)
         }
     }
 
-    version = std::max(statedVersion, version);
-    if (version == 0) {
-        // if missing version, we'll assume version 1...
-        version = 1;
-    }
-
-    if (version != 1) {
-        char msg[128];
-        ai_snprintf(msg, 128, "GLTF: Unsupported glTF version: %.0f", version);
-        throw DeadlyImportError(msg);
+    if (version.empty() || version[0] != '1') {
+        throw DeadlyImportError("GLTF: Unsupported glTF version: " + version);
     }
 }
 
@@ -1273,7 +1282,7 @@ inline void Asset::ReadBinaryHeader(IOStream& stream)
     }
 
     AI_SWAP4(header.version);
-    asset.version = header.version;
+    asset.version = std::to_string(header.version);
     if (header.version != 1) {
         throw DeadlyImportError("GLTF: Unsupported binary glTF version");
     }

+ 2 - 7
code/glTFAssetWriter.inl

@@ -606,13 +606,8 @@ namespace glTF {
     {
         Value asset;
         asset.SetObject();
-        {
-            char versionChar[10];
-            ai_snprintf(versionChar, sizeof(versionChar), "%.0f", mAsset.asset.version);
-            asset.AddMember("version", Value(versionChar, mAl).Move(), mAl);
-
-            asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
-        }
+        asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
+        asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
         mDoc.AddMember("asset", asset, mAl);
     }
 

+ 5 - 5
code/glTFExporter.cpp

@@ -507,7 +507,7 @@ void glTFExporter::ExportMeshes()
 
     // Variables needed for compression. BEGIN.
     // Indices, not pointers - because pointer to buffer is changing while writing to it.
-    size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
+    size_t idx_srcdata_begin = 0; // Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
     size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
     std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
     size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
@@ -875,7 +875,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             timeData[i] = nodeChannel->mPositionKeys[frameIndex].mTime / ticksPerSecond;
         }
 
-        Ref<Accessor> timeAccessor = ExportData(mAsset, animId, buffer, numKeyframes, &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT);
+        Ref<Accessor> timeAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT);
         if (timeAccessor) animRef->Parameters.TIME = timeAccessor;
     }
 
@@ -888,7 +888,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             translationData[i] = nodeChannel->mPositionKeys[frameIndex].mValue;
         }
 
-        Ref<Accessor> tranAccessor = ExportData(mAsset, animId, buffer, numKeyframes, translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+        Ref<Accessor> tranAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
         if ( tranAccessor ) {
             animRef->Parameters.translation = tranAccessor;
         }
@@ -904,7 +904,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             scaleData[i] = nodeChannel->mScalingKeys[frameIndex].mValue;
         }
 
-        Ref<Accessor> scaleAccessor = ExportData(mAsset, animId, buffer, numKeyframes, scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+        Ref<Accessor> scaleAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
         if ( scaleAccessor ) {
             animRef->Parameters.scale = scaleAccessor;
         }
@@ -923,7 +923,7 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animati
             rotationData[i][3] = nodeChannel->mRotationKeys[frameIndex].mValue.w;
         }
 
-        Ref<Accessor> rotAccessor = ExportData(mAsset, animId, buffer, numKeyframes, rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
+        Ref<Accessor> rotAccessor = ExportData(mAsset, animId, buffer, static_cast<unsigned int>(numKeyframes), rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
         if ( rotAccessor ) {
             animRef->Parameters.rotation = rotAccessor;
         }

+ 13 - 18
code/glTFImporter.cpp

@@ -100,24 +100,19 @@ const aiImporterDesc* glTFImporter::GetInfo() const
 
 bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-    const std::string& extension = GetExtension(pFile);
-
-    if (extension == "gltf" || extension == "glb")
-        return true;
-
-    if ((checkSig || !extension.length()) && pIOHandler) {
-        char buffer[4];
-
-        std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
-        if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) {
-            if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) {
-                return true; // Has GLB header
-            }
-            else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0
-                    || memcmp(buffer, "{\n  ", sizeof(buffer)) == 0) {
-                // seems a JSON file, and we're the only format that can read them
-                return true;
-            }
+    const std::string &extension = GetExtension(pFile);
+
+    if (extension != "gltf" && extension != "glb")
+        return false;
+
+    if (checkSig && pIOHandler) {
+        glTF::Asset asset(pIOHandler);
+        try {
+            asset.Load(pFile, extension == "glb");
+            std::string version = asset.asset.version;
+            return !version.empty() && version[0] == '1';
+        } catch (...) {
+            return false;
         }
     }
 

+ 5 - 0
contrib/irrXML/CMakeLists.txt

@@ -8,6 +8,11 @@ set( IrrXML_SRCS
   irrXML.h
 )
 
+if ( MSVC )
+  ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
+  ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
+endif ( MSVC )
+
 add_library(IrrXML STATIC ${IrrXML_SRCS})
 set(IRRXML_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "IrrXML_Include" )
 set(IRRXML_LIBRARY "IrrXML" CACHE INTERNAL "IrrXML" )

+ 3 - 2
test/CMakeLists.txt

@@ -65,7 +65,7 @@ SET( TEST_SRCS
   unit/ut3DSImportExport.cpp
   unit/utACImportExport.cpp
   unit/utAMFImportExport.cpp
-  unit/utASEImportExport.cpp  
+  unit/utASEImportExport.cpp
   unit/utAnim.cpp
   unit/AssimpAPITest.cpp
   unit/utB3DImportExport.cpp
@@ -88,6 +88,7 @@ SET( TEST_SRCS
   unit/utFixInfacingNormals.cpp
   unit/utGenNormals.cpp
   unit/utglTFImportExport.cpp
+  unit/utglTF2ImportExport.cpp
   unit/utHMPImportExport.cpp
   unit/utIFCImportExport.cpp
   unit/utImporter.cpp
@@ -146,7 +147,7 @@ add_executable( unit
 )
 
 add_definitions(-DASSIMP_TEST_MODELS_DIR="${CMAKE_CURRENT_LIST_DIR}/models")
-    
+
 SET_PROPERTY( TARGET assimp PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} )
 
 IF( WIN32 )

BIN
test/models/glTF2/BoxTextured-glTF-Binary/BoxTextured.glb


File diff suppressed because it is too large
+ 141 - 0
test/models/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf


+ 197 - 0
test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf

@@ -0,0 +1,197 @@
+{
+    "asset": {
+        "generator": "COLLADA2GLTF",
+        "version": "2.0"
+    },
+    "scene": 0,
+    "scenes": [
+        {
+            "nodes": [
+                0
+            ]
+        }
+    ],
+    "nodes": [
+        {
+            "children": [
+                1
+            ],
+            "matrix": [
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                -1.0,
+                0.0,
+                0.0,
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ]
+        },
+        {
+            "mesh": 0
+        }
+    ],
+    "meshes": [
+        {
+            "primitives": [
+                {
+                    "attributes": {
+                        "NORMAL": 1,
+                        "POSITION": 2,
+                        "TEXCOORD_0": 3
+                    },
+                    "indices": 0,
+                    "mode": 4,
+                    "material": 0
+                }
+            ],
+            "name": "Mesh"
+        }
+    ],
+    "accessors": [
+        {
+            "bufferView": 0,
+            "byteOffset": 0,
+            "componentType": 5123,
+            "count": 36,
+            "max": [
+                23
+            ],
+            "min": [
+                0
+            ],
+            "type": "SCALAR"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "min": [
+                -1.0,
+                -1.0,
+                -1.0
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 288,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                0.5,
+                0.5,
+                0.5
+            ],
+            "min": [
+                -0.5,
+                -0.5,
+                -0.5
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 2,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                6.0,
+                1.0
+            ],
+            "min": [
+                0.0,
+                0.0
+            ],
+            "type": "VEC2"
+        }
+    ],
+    "materials": [
+        {
+            "pbrMetallicRoughness": {
+                "baseColorTexture": {
+                    "index": 0
+                },
+                "metallicFactor": 0.0
+            },
+            "extensions": {
+                "KHR_materials_pbrSpecularGlossiness": {
+                    "diffuseTexture": {
+                        "index": 0
+                    },
+                    "specularFactor": [
+                        0.20000000298023225,
+                        0.20000000298023225,
+                        0.20000000298023225
+                    ],
+                    "glossinessFactor": 1.0
+                }
+            },
+            "name": "Texture"
+        }
+    ],
+    "textures": [
+        {
+            "sampler": 0,
+            "source": 0
+        }
+    ],
+    "images": [
+        {
+            "uri": "CesiumLogoFlat.png"
+        }
+    ],
+    "samplers": [
+        {
+            "magFilter": 9729,
+            "minFilter": 9986,
+            "wrapS": 10497,
+            "wrapT": 10497
+        }
+    ],
+    "bufferViews": [
+        {
+            "buffer": 0,
+            "byteOffset": 768,
+            "byteLength": 72,
+            "target": 34963
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 0,
+            "byteLength": 576,
+            "byteStride": 12,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 576,
+            "byteLength": 192,
+            "byteStride": 8,
+            "target": 34962
+        }
+    ],
+    "buffers": [
+        {
+            "byteLength": 840,
+            "uri": "BoxTextured0.bin"
+        }
+    ],
+    "extensionsUsed": [
+        "KHR_materials_pbrSpecularGlossiness"
+    ]
+}

BIN
test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured0.bin


BIN
test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/CesiumLogoFlat.png


+ 282 - 0
test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured.gltf

@@ -0,0 +1,282 @@
+{
+    "asset": {
+        "generator": "COLLADA2GLTF",
+        "version": "2.0"
+    },
+    "scene": 0,
+    "scenes": [
+        {
+            "nodes": [
+                0
+            ]
+        }
+    ],
+    "nodes": [
+        {
+            "children": [
+                1
+            ],
+            "matrix": [
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                -1.0,
+                0.0,
+                0.0,
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ]
+        },
+        {
+            "mesh": 0
+        }
+    ],
+    "meshes": [
+        {
+            "primitives": [
+                {
+                    "attributes": {
+                        "NORMAL": 1,
+                        "POSITION": 2,
+                        "TEXCOORD_0": 3
+                    },
+                    "indices": 0,
+                    "mode": 4,
+                    "material": 0
+                }
+            ],
+            "name": "Mesh"
+        }
+    ],
+    "accessors": [
+        {
+            "bufferView": 0,
+            "byteOffset": 0,
+            "componentType": 5123,
+            "count": 36,
+            "max": [
+                23
+            ],
+            "min": [
+                0
+            ],
+            "type": "SCALAR"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "min": [
+                -1.0,
+                -1.0,
+                -1.0
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 288,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                0.5,
+                0.5,
+                0.5
+            ],
+            "min": [
+                -0.5,
+                -0.5,
+                -0.5
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 2,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                6.0,
+                1.0
+            ],
+            "min": [
+                0.0,
+                0.0
+            ],
+            "type": "VEC2"
+        }
+    ],
+    "materials": [
+        {
+            "values": {
+                "diffuse": [
+                    0
+                ],
+                "specular": [
+                    0.20000000298023225,
+                    0.20000000298023225,
+                    0.20000000298023225,
+                    1.0
+                ],
+                "shininess": [
+                    256.0
+                ],
+                "transparency": [
+                    1.0
+                ]
+            },
+            "technique": 0
+        }
+    ],
+    "textures": [
+        {
+            "sampler": 0,
+            "source": 0
+        }
+    ],
+    "images": [
+        {
+            "uri": "CesiumLogoFlat.png"
+        }
+    ],
+    "samplers": [
+        {
+            "magFilter": 9729,
+            "minFilter": 9986,
+            "wrapS": 10497,
+            "wrapT": 10497
+        }
+    ],
+    "techniques": [
+        {
+            "attributes": {
+                "a_normal": "normal",
+                "a_position": "position",
+                "a_texcoord0": "texcoord0"
+            },
+            "parameters": {
+                "diffuse": {
+                    "type": 35678
+                },
+                "modelViewMatrix": {
+                    "semantic": "MODELVIEW",
+                    "type": 35676
+                },
+                "normal": {
+                    "semantic": "NORMAL",
+                    "type": 35665
+                },
+                "normalMatrix": {
+                    "semantic": "MODELVIEWINVERSETRANSPOSE",
+                    "type": 35675
+                },
+                "position": {
+                    "semantic": "POSITION",
+                    "type": 35665
+                },
+                "projectionMatrix": {
+                    "semantic": "PROJECTION",
+                    "type": 35676
+                },
+                "shininess": {
+                    "type": 5126
+                },
+                "specular": {
+                    "type": 35666
+                },
+                "texcoord0": {
+                    "semantic": "TEXCOORD_0",
+                    "type": 35665
+                },
+                "transparency": {
+                    "type": 5126
+                }
+            },
+            "program": 0,
+            "states": {
+                "enable": [
+                    2884,
+                    2929
+                ]
+            },
+            "uniforms": {
+                "u_diffuse": "diffuse",
+                "u_modelViewMatrix": "modelViewMatrix",
+                "u_normalMatrix": "normalMatrix",
+                "u_projectionMatrix": "projectionMatrix",
+                "u_shininess": "shininess",
+                "u_specular": "specular",
+                "u_transparency": "transparency"
+            }
+        }
+    ],
+    "programs": [
+        {
+            "attributes": [
+                "a_normal",
+                "a_position",
+                "a_texcoord0"
+            ],
+            "fragmentShader": 1,
+            "vertexShader": 0
+        }
+    ],
+    "shaders": [
+        {
+            "type": 35633,
+            "uri": "BoxTextured0.vert"
+        },
+        {
+            "type": 35632,
+            "uri": "BoxTextured1.frag"
+        }
+    ],
+    "bufferViews": [
+        {
+            "buffer": 0,
+            "byteOffset": 768,
+            "byteLength": 72,
+            "target": 34963
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 0,
+            "byteLength": 576,
+            "byteStride": 12,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 576,
+            "byteLength": 192,
+            "byteStride": 8,
+            "target": 34962
+        }
+    ],
+    "buffers": [
+        {
+            "byteLength": 840,
+            "uri": "BoxTextured0.bin"
+        }
+    ],
+    "extensionsRequired": [
+        "KHR_technique_webgl"
+    ],
+    "extensionsUsed": [
+        "KHR_technique_webgl"
+    ]
+}

BIN
test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.bin


+ 17 - 0
test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.vert

@@ -0,0 +1,17 @@
+precision highp float;
+uniform mat4 u_modelViewMatrix;
+uniform mat4 u_projectionMatrix;
+uniform mat3 u_normalMatrix;
+attribute vec3 a_position;
+varying vec3 v_position;
+attribute vec3 a_normal;
+varying vec3 v_normal;
+attribute vec2 a_texcoord0;
+varying vec2 v_texcoord0;
+void main(void) {
+    vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);
+    v_position = pos.xyz;
+    gl_Position = u_projectionMatrix * pos;
+    v_normal = u_normalMatrix * a_normal;
+    v_texcoord0 = a_texcoord0;
+}

+ 29 - 0
test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured1.frag

@@ -0,0 +1,29 @@
+precision highp float;
+uniform sampler2D u_diffuse;
+uniform vec4 u_specular;
+uniform float u_shininess;
+uniform float u_transparency;
+varying vec3 v_position;
+varying vec3 v_normal;
+varying vec2 v_texcoord0;
+void main(void) {
+    vec3 normal = normalize(v_normal);
+    vec4 diffuse = texture2D(u_diffuse, v_texcoord0);
+    vec3 diffuseLight = vec3(0.0, 0.0, 0.0);
+    vec3 specular = u_specular.rgb;
+    vec3 specularLight = vec3(0.0, 0.0, 0.0);
+    vec3 ambient = diffuse.rgb;
+    vec3 viewDir = -normalize(v_position);
+    vec3 ambientLight = vec3(0.0, 0.0, 0.0);
+    ambientLight += vec3(0.2, 0.2, 0.2);
+    vec3 l = vec3(0.0, 0.0, 1.0);
+    diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal, l), 0.); 
+    vec3 reflectDir = reflect(-l, normal);
+    float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));
+    specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity;
+    vec3 color = vec3(0.0, 0.0, 0.0);
+    color += diffuse.rgb * diffuseLight;
+    color += specular * specularLight;
+    color += ambient * ambientLight;
+    gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);
+}

BIN
test/models/glTF2/BoxTextured-glTF-techniqueWebGL/CesiumLogoFlat.png


+ 181 - 0
test/models/glTF2/BoxTextured-glTF/BoxTextured.gltf

@@ -0,0 +1,181 @@
+{
+    "asset": {
+        "generator": "COLLADA2GLTF",
+        "version": "2.0"
+    },
+    "scene": 0,
+    "scenes": [
+        {
+            "nodes": [
+                0
+            ]
+        }
+    ],
+    "nodes": [
+        {
+            "children": [
+                1
+            ],
+            "matrix": [
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                -1.0,
+                0.0,
+                0.0,
+                1.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ]
+        },
+        {
+            "mesh": 0
+        }
+    ],
+    "meshes": [
+        {
+            "primitives": [
+                {
+                    "attributes": {
+                        "NORMAL": 1,
+                        "POSITION": 2,
+                        "TEXCOORD_0": 3
+                    },
+                    "indices": 0,
+                    "mode": 4,
+                    "material": 0
+                }
+            ],
+            "name": "Mesh"
+        }
+    ],
+    "accessors": [
+        {
+            "bufferView": 0,
+            "byteOffset": 0,
+            "componentType": 5123,
+            "count": 36,
+            "max": [
+                23
+            ],
+            "min": [
+                0
+            ],
+            "type": "SCALAR"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "min": [
+                -1.0,
+                -1.0,
+                -1.0
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 1,
+            "byteOffset": 288,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                0.5,
+                0.5,
+                0.5
+            ],
+            "min": [
+                -0.5,
+                -0.5,
+                -0.5
+            ],
+            "type": "VEC3"
+        },
+        {
+            "bufferView": 2,
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 24,
+            "max": [
+                6.0,
+                1.0
+            ],
+            "min": [
+                0.0,
+                0.0
+            ],
+            "type": "VEC2"
+        }
+    ],
+    "materials": [
+        {
+            "pbrMetallicRoughness": {
+                "baseColorTexture": {
+                    "index": 0
+                },
+                "metallicFactor": 0.0
+            },
+            "name": "Texture"
+        }
+    ],
+    "textures": [
+        {
+            "sampler": 0,
+            "source": 0
+        }
+    ],
+    "images": [
+        {
+            "uri": "CesiumLogoFlat.png"
+        }
+    ],
+    "samplers": [
+        {
+            "magFilter": 9729,
+            "minFilter": 9986,
+            "wrapS": 10497,
+            "wrapT": 10497
+        }
+    ],
+    "bufferViews": [
+        {
+            "buffer": 0,
+            "byteOffset": 768,
+            "byteLength": 72,
+            "target": 34963
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 0,
+            "byteLength": 576,
+            "byteStride": 12,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteOffset": 576,
+            "byteLength": 192,
+            "byteStride": 8,
+            "target": 34962
+        }
+    ],
+    "buffers": [
+        {
+            "byteLength": 840,
+            "uri": "BoxTextured0.bin"
+        }
+    ]
+}

BIN
test/models/glTF2/BoxTextured-glTF/BoxTextured0.bin


BIN
test/models/glTF2/BoxTextured-glTF/CesiumLogoFlat.png


+ 80 - 0
test/unit/utglTF2ImportExport.cpp

@@ -0,0 +1,80 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "AbstractImportExportBase.h"
+
+#include <assimp/Importer.hpp>
+#include <assimp/Exporter.hpp>
+
+using namespace Assimp;
+
+class utglTF2ImportExport : public AbstractImportExportBase {
+public:
+    virtual bool importerTest() {
+        Assimp::Importer importer;
+        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", 0);
+        return nullptr != scene;
+    }
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+    virtual bool exporterTest() {
+        Assimp::Importer importer;
+        Assimp::Exporter exporter;
+        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", 0 );
+        EXPECT_NE( nullptr, scene );
+        EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf" ) );
+
+        return true;
+    }
+#endif // ASSIMP_BUILD_NO_EXPORT
+
+};
+
+TEST_F( utglTF2ImportExport, importglTF2FromFileTest ) {
+    EXPECT_TRUE( importerTest() );
+}
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) {
+    EXPECT_TRUE( exporterTest() );
+}
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 1 - 1
test/unit/utglTFImportExport.cpp

@@ -55,6 +55,6 @@ public:
     }
 };
 
-TEST_F( utglTFImportExport, importglTFromFileTest ) {
+TEST_F( utglTFImportExport, importglTFFromFileTest ) {
     EXPECT_TRUE( importerTest() );
 }

Some files were not shown because too many files changed in this diff