Browse Source

Merge branch '3mf_basematerial_support' of https://github.com/assimp/assimp into 3mf_basematerial_support

Kim Kulling 7 years ago
parent
commit
c5c0052a6c

+ 5 - 0
CMakeLists.txt

@@ -230,6 +230,11 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
   ADD_DEFINITIONS( -U__STRICT_ANSI__ )
 ENDIF()
 
+if (IOS)
+    set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fembed-bitcode -O3")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
+endif()
+
 if (ASSIMP_COVERALLS)
     MESSAGE(STATUS "Coveralls enabled")
     INCLUDE(Coveralls)

+ 1 - 1
code/3DSLoader.cpp

@@ -349,7 +349,7 @@ void Discreet3DSImporter::ParseObjectChunk()
     case Discreet3DS::CHUNK_MAT_MATERIAL:
 
         // Add a new material to the list
-        mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + std::to_string(mScene->mMaterials.size()))));
+        mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + to_string(mScene->mMaterials.size()))));
         ParseMaterialChunk();
         break;
 

+ 1 - 0
code/CMakeLists.txt

@@ -72,6 +72,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/matrix4x4.h
   ${HEADER_PATH}/matrix4x4.inl
   ${HEADER_PATH}/mesh.h
+  ${HEADER_PATH}/pbrmaterial.h
   ${HEADER_PATH}/postprocess.h
   ${HEADER_PATH}/quaternion.h
   ${HEADER_PATH}/quaternion.inl

+ 6 - 0
code/ColladaLoader.cpp

@@ -131,6 +131,7 @@ void ColladaLoader::SetupProperties(const Importer* pImp)
 {
     noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
     ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
+    useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1913,6 +1914,11 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
 // The name must be unique for proper node-bone association.
 std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
 {
+    // If explicitly requested, just use the collada name.
+    if (useColladaName) {
+        return pNode->mName;
+    }
+
     // Now setup the name of the assimp node. The collada name might not be
     // unique, so we use the collada ID.
     if (!pNode->mID.empty())

+ 1 - 0
code/ColladaLoader.h

@@ -248,6 +248,7 @@ protected:
 
     bool noSkeletonMesh;
     bool ignoreUpDirection;
+    bool useColladaName;
 
     /** Used by FindNameForNode() to generate unique node names */
     unsigned int mNodeNameCounter;

+ 5 - 3
code/FBXExporter.cpp

@@ -235,9 +235,6 @@ void FBXExporter::WriteBinaryFooter()
     outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1);
 
     outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
-    for (size_t i = 0; i < 4; ++i) {
-        outfile->Write("\x00", 1, 1);
-    }
 
     // here some padding is added for alignment to 16 bytes.
     // if already aligned, the full 16 bytes is added.
@@ -247,6 +244,11 @@ void FBXExporter::WriteBinaryFooter()
         outfile->Write("\x00", 1, 1);
     }
 
+    // not sure what this is, but it seems to always be 0 in modern files
+    for (size_t i = 0; i < 4; ++i) {
+        outfile->Write("\x00", 1, 1);
+    }
+
     // now the file version again
     {
         StreamWriterLE outstream(outfile);

+ 6 - 3
code/FBXMaterial.cpp

@@ -54,6 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXProperties.h"
 #include <assimp/ByteSwapper.h>
 
+#include <algorithm> // std::transform
+
 namespace Assimp {
 namespace FBX {
 
@@ -82,11 +84,12 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
 
     std::string templateName;
 
-    const char* const sh = shading.c_str();
-    if(!strcmp(sh,"phong")) {
+    // lower-case shading because Blender (for example) writes "Phong"
+    std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower);
+    if(shading == "phong") {
         templateName = "Material.FbxSurfacePhong";
     }
-    else if(!strcmp(sh,"lambert")) {
+    else if(shading == "lambert") {
         templateName = "Material.FbxSurfaceLambert";
     }
     else {

+ 3 - 2
code/ObjFileMtlImporter.cpp

@@ -303,11 +303,12 @@ void ObjFileMtlImporter::createMaterial()
         // New Material created
         m_pModel->m_pCurrentMaterial = new ObjFile::Material();
         m_pModel->m_pCurrentMaterial->MaterialName.Set( name );
+        m_pModel->m_MaterialLib.push_back( name );
+        m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial;
+
         if (m_pModel->m_pCurrentMesh) {
             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;
     } else {
         // Use older material
         m_pModel->m_pCurrentMaterial = (*it).second;

+ 1 - 22
code/PlyLoader.cpp

@@ -245,28 +245,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
     // list is containing a list of points
     bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
     if (pointsOnly) {
-        if (mGeneratedMesh->mNumVertices < 3) {
-            if (mGeneratedMesh != NULL) {
-                delete(mGeneratedMesh);
-                mGeneratedMesh = nullptr;
-            }
-
-            streamedBuffer.close();
-            throw DeadlyImportError("Invalid .ply file: Not enough "
-                    "vertices to build a proper face list. ");
-        }
-
-        const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3;
-        mGeneratedMesh->mNumFaces = iNum;
-        mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
-
-        for (unsigned int i = 0; i < iNum; ++i) {
-            mGeneratedMesh->mFaces[i].mNumIndices = 3;
-            mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3];
-            mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3);
-            mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1;
-            mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2;
-        }
+      mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
     }
 
     // now load a list of all materials

+ 44 - 24
code/PlyParser.cpp

@@ -1043,71 +1043,91 @@ bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
   switch (eType)
   {
   case EDT_UInt:
-    out->iUInt = (uint32_t)*((uint32_t*)pCur);
-    pCur += 4;
+  {
+    uint32_t t;
+    memcpy(&t, pCur, sizeof(uint32_t));
+    pCur += sizeof(uint32_t);
 
     // Swap endianness
-    if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
+    if (p_bBE)ByteSwap::Swap(&t);
+    out->iUInt = t;
     break;
+  }
 
   case EDT_UShort:
   {
-    uint16_t i = *((uint16_t*)pCur);
+    uint16_t t;
+    memcpy(&t, pCur, sizeof(uint16_t));
+    pCur += sizeof(uint16_t);
 
     // Swap endianness
-    if (p_bBE)ByteSwap::Swap(&i);
-    out->iUInt = (uint32_t)i;
-    pCur += 2;
+    if (p_bBE)ByteSwap::Swap(&t);
+    out->iUInt = t;
     break;
   }
 
   case EDT_UChar:
   {
-    out->iUInt = (uint32_t)(*((uint8_t*)pCur));
-    pCur++;
+    uint8_t t;
+    memcpy(&t, pCur, sizeof(uint8_t));
+    pCur += sizeof(uint8_t);
+    out->iUInt = t;
     break;
   }
 
   case EDT_Int:
-    out->iInt = *((int32_t*)pCur);
-    pCur += 4;
+  {
+    int32_t t;
+    memcpy(&t, pCur, sizeof(int32_t));
+    pCur += sizeof(int32_t);
 
     // Swap endianness
-    if (p_bBE)ByteSwap::Swap(&out->iInt);
+    if (p_bBE)ByteSwap::Swap(&t);
+    out->iInt = t;
     break;
+  }
 
   case EDT_Short:
   {
-    int16_t i = *((int16_t*)pCur);
+    int16_t t;
+    memcpy(&t, pCur, sizeof(int16_t));
+    pCur += sizeof(int16_t);
 
     // Swap endianness
-    if (p_bBE)ByteSwap::Swap(&i);
-    out->iInt = (int32_t)i;
-    pCur += 2;
+    if (p_bBE)ByteSwap::Swap(&t);
+    out->iInt = t;
     break;
   }
 
   case EDT_Char:
-    out->iInt = (int32_t)*((int8_t*)pCur);
-    pCur++;
+  {
+    int8_t t;
+    memcpy(&t, pCur, sizeof(int8_t));
+    pCur += sizeof(int8_t);
+    out->iInt = t;
     break;
+  }
 
   case EDT_Float:
   {
-    out->fFloat = *((float*)pCur);
+    float t;
+    memcpy(&t, pCur, sizeof(float));
+    pCur += sizeof(float);
 
     // Swap endianness
-    if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
-    pCur += 4;
+    if (p_bBE)ByteSwap::Swap(&t);
+    out->fFloat = t;
     break;
   }
   case EDT_Double:
   {
-    out->fDouble = *((double*)pCur);
+    double t;
+    memcpy(&t, pCur, sizeof(double));
+    pCur += sizeof(double);
 
     // Swap endianness
-    if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
-    pCur += 8;
+    if (p_bBE)ByteSwap::Swap(&t);
+    out->fDouble = t;
     break;
   }
   default:

+ 6 - 2
code/STLExporter.cpp

@@ -172,12 +172,16 @@ void STLExporter :: WriteMeshBinary(const aiMesh* m)
             }
             nor.Normalize();
         }
-        ai_real nx = nor.x, ny = nor.y, nz = nor.z;
+        // STL binary files use 4-byte floats. This may possibly cause loss of precision
+        // for clients using 8-byte doubles
+        float nx = (float) nor.x;
+        float ny = (float) nor.y;
+        float nz = (float) nor.z;
         AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz);
         mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4);
         for(unsigned int a = 0; a < f.mNumIndices; ++a) {
             const aiVector3D& v  = m->mVertices[f.mIndices[a]];
-            ai_real vx = v.x, vy = v.y, vz = v.z;
+            float vx = (float) v.x, vy = (float) v.y, vz = (float) v.z;
             AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz);
             mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4);
         }

+ 14 - 1
code/glTF2Asset.inl

@@ -669,7 +669,7 @@ inline Image::Image()
 
 }
 
-inline void Image::Read(Value& obj, Asset& /*r*/)
+inline void Image::Read(Value& obj, Asset& r)
 {
     if (!mDataLength) {
         if (Value* uri = FindString(obj, "uri")) {
@@ -686,6 +686,19 @@ inline void Image::Read(Value& obj, Asset& /*r*/)
                 this->uri = uristr;
             }
         }
+        else if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
+            this->bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
+            Ref<Buffer> buffer = this->bufferView->buffer;
+
+            this->mDataLength = this->bufferView->byteLength;
+            // maybe this memcpy could be avoided if aiTexture does not delete[] pcData at destruction.
+            this->mData = new uint8_t [this->mDataLength];
+            memcpy(this->mData, buffer->GetPointer() + this->bufferView->byteOffset, this->mDataLength);
+
+            if (Value* mtype = FindString(obj, "mimeType")) {
+                this->mimeType = mtype->GetString();
+            }
+        }
     }
 }
 

+ 8 - 8
code/glTFAsset.inl

@@ -948,24 +948,24 @@ Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
 	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) + ").");
+		throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + to_string(size_coordindex) +
+								") not equal to uncompressed (" + 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) + ").");
+		throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + to_string(size_coord) +
+								") not equal to uncompressed (" + 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) + ").");
+		throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + to_string(size_normal) +
+								") not equal to uncompressed (" + to_string(primitives[0].attributes.normal[0]->count) + ").");
 
 	size_normal *= 3 * sizeof(float);
 	// Additional attributes.
@@ -989,8 +989,8 @@ Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
 				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) + ").");
+						throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + to_string(tval) +
+												") not equal to uncompressed (" + to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
 
 					idx_texcoord++;
 				}

+ 9 - 2
code/glTFImporter.cpp

@@ -194,9 +194,16 @@ void glTFImporter::ImportMaterials(glTF::Asset& r)
             aimat->AddProperty(&str, AI_MATKEY_NAME);
         }
 
-        SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
+        SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient,  aimat, aiTextureType_AMBIENT,  AI_MATKEY_COLOR_AMBIENT );
+        SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse,  aimat, aiTextureType_DIFFUSE,  AI_MATKEY_COLOR_DIFFUSE );
         SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
-        SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
+        SetMaterialColorProperty(embeddedTexIdxs, r, mat.emission, aimat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE);
+
+        aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
+
+        if (mat.transparent && (mat.transparency != 1.0f)) {
+            aimat->AddProperty(&mat.transparency, 1, AI_MATKEY_OPACITY);
+        }
 
         if (mat.shininess > 0.f) {
             aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);

+ 3 - 2
contrib/zlib/zlib.h

@@ -77,8 +77,9 @@ extern "C" {
   the consistency of the compressed data, so the library should never crash
   even in the case of corrupted input.
 */
-#ifdef __ANDROID__     
-using zcrc_t = unsigned_long; 
+
+#ifdef __ANDROID__
+typedef unsigned long zcrc_t;
 #endif
 
 typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));

+ 10 - 0
include/assimp/config.h.in

@@ -934,6 +934,16 @@ enum aiComponent
  */
 #define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION"
 
+// ---------------------------------------------------------------------------
+/** @brief Specifies whether the Collada loader should use Collada names as node names.
+ *
+ * If this property is set to true, the Collada names will be used as the
+ * node name. The default is to use the id tag (resp. sid tag, if no id tag is present)
+ * instead.
+ * Property type: Bool. Default value: false.
+ */
+#define AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES "IMPORT_COLLADA_USE_COLLADA_NAMES"
+
 // ---------- All the Export defines ------------
 
 /** @brief Specifies the xfile use double for real values of float

+ 5 - 0
test/models/OBJ/cube_mtllib_after_g.mtl

@@ -0,0 +1,5 @@
+newmtl MyMaterial
+Ka 1.000 1.000 1.000
+Kd 1.000 1.000 1.000
+Ns 200.000
+Ks 0.050 0.050 0.050

+ 32 - 0
test/models/OBJ/cube_mtllib_after_g.obj

@@ -0,0 +1,32 @@
+g Object
+mtllib cube_mtllib_after_g.mat
+usemtl MyMaterial
+
+v  0.0  0.0  0.0
+v  0.0  0.0  1.0
+v  0.0  1.0  0.0
+v  0.0  1.0  1.0
+v  1.0  0.0  0.0
+v  1.0  0.0  1.0
+v  1.0  1.0  0.0
+v  1.0  1.0  1.0
+
+vn  0.0  0.0  1.0
+vn  0.0  0.0 -1.0
+vn  0.0  1.0  0.0
+vn  0.0 -1.0  0.0
+vn  1.0  0.0  0.0
+vn -1.0  0.0  0.0
+
+f  1//2  7//2  5//2
+f  1//2  3//2  7//2 
+f  1//6  4//6  3//6 
+f  1//6  2//6  4//6 
+f  3//3  8//3  7//3 
+f  3//3  4//3  8//3 
+f  5//5  7//5  8//5 
+f  5//5  8//5  6//5 
+f  1//4  5//4  6//4 
+f  1//4  6//4  2//4 
+f  2//1  6//1  8//1 
+f  2//1  8//1  4//1 

BIN
test/models/PLY/cube_binary.ply


+ 45 - 0
test/models/PLY/cube_uv.ply

@@ -0,0 +1,45 @@
+ply
+format ascii 1.0
+comment Created by Blender 2.77 (sub 0) - www.blender.org, source file: ''
+element vertex 24
+property float x
+property float y
+property float z
+property float nx
+property float ny
+property float nz
+property float s
+property float t
+element face 6
+property list uchar uint vertex_indices
+end_header
+1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000 0.000000
+1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000 1.000000 0.000000
+-1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000 1.000000 1.000000
+-1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000 1.000000
+1.000000 0.999999 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000
+-1.000000 1.000000 1.000000 0.000000 -0.000000 1.000000 1.000000 0.000000
+-1.000000 -1.000000 1.000000 0.000000 -0.000000 1.000000 1.000000 1.000000
+0.999999 -1.000001 1.000000 0.000000 -0.000000 1.000000 0.000000 1.000000
+1.000000 1.000000 -1.000000 1.000000 -0.000000 0.000000 0.000000 0.000000
+1.000000 0.999999 1.000000 1.000000 -0.000000 0.000000 1.000000 0.000000
+0.999999 -1.000001 1.000000 1.000000 -0.000000 0.000000 1.000000 1.000000
+1.000000 -1.000000 -1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000
+1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000 0.000000 0.000000
+0.999999 -1.000001 1.000000 -0.000000 -1.000000 -0.000000 1.000000 0.000000
+-1.000000 -1.000000 1.000000 -0.000000 -1.000000 -0.000000 1.000000 1.000000
+-1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000 0.000000 1.000000
+-1.000000 -1.000000 -1.000000 -1.000000 0.000000 -0.000000 0.000000 0.000000
+-1.000000 -1.000000 1.000000 -1.000000 0.000000 -0.000000 1.000000 0.000000
+-1.000000 1.000000 1.000000 -1.000000 0.000000 -0.000000 1.000000 1.000000
+-1.000000 1.000000 -1.000000 -1.000000 0.000000 -0.000000 0.000000 1.000000
+1.000000 0.999999 1.000000 0.000000 1.000000 0.000000 0.000000 0.000000
+1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000 1.000000 0.000000
+-1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000 1.000000 1.000000
+-1.000000 1.000000 1.000000 0.000000 1.000000 0.000000 0.000000 1.000000
+4 0 1 2 3
+4 4 5 6 7
+4 8 9 10 11
+4 12 13 14 15
+4 16 17 18 19
+4 20 21 22 23

+ 1 - 1
test/models/PLY/float-color.ply

@@ -15,4 +15,4 @@ end_header
 0.0 0.0 0.0 0 0 1 1
 100.0 0.0 0.0 0 0 1 1
 200.0 200.0 0.0 0 0 1 1
-3 0 1 2
+3 0 1 2

+ 36 - 0
test/models/PLY/issue623.ply

@@ -0,0 +1,36 @@
+ply
+format ascii 1.0
+comment Created by Blender 2.77 (sub 0) - www.blender.org, source file: ''
+element vertex 24
+property float x
+property float y
+property float z
+property float nx
+property float ny
+property float nz
+property list uchar uint vertex_indices
+end_header
+7.941797 1.432409 -0.927566 0.000000 0.000000 -1.000000
+7.941797 -2.321273 -0.927566 0.000000 0.000000 -1.000000
+4.188114 -2.321273 -0.927566 0.000000 0.000000 -1.000000
+4.188115 1.432410 -0.927566 0.000000 0.000000 -1.000000
+7.941798 1.432408 2.826117 0.000000 -0.000000 1.000000
+4.188114 1.432409 2.826117 0.000000 -0.000000 1.000000
+4.188113 -2.321273 2.826117 0.000000 -0.000000 1.000000
+7.941795 -2.321275 2.826117 0.000000 -0.000000 1.000000
+7.941797 1.432409 -0.927566 1.000000 -0.000000 0.000000
+7.941798 1.432408 2.826117 1.000000 -0.000000 0.000000
+7.941795 -2.321275 2.826117 1.000000 -0.000000 0.000000
+7.941797 -2.321273 -0.927566 1.000000 -0.000000 0.000000
+7.941797 -2.321273 -0.927566 -0.000000 -1.000000 -0.000000
+7.941795 -2.321275 2.826117 -0.000000 -1.000000 -0.000000
+4.188113 -2.321273 2.826117 -0.000000 -1.000000 -0.000000
+4.188114 -2.321273 -0.927566 -0.000000 -1.000000 -0.000000
+4.188114 -2.321273 -0.927566 -1.000000 0.000000 -0.000000
+4.188113 -2.321273 2.826117 -1.000000 0.000000 -0.000000
+4.188114 1.432409 2.826117 -1.000000 0.000000 -0.000000
+4.188115 1.432410 -0.927566 -1.000000 0.000000 -0.000000
+7.941798 1.432408 2.826117 0.000000 1.000000 0.000000
+7.941797 1.432409 -0.927566 0.000000 1.000000 0.000000
+4.188115 1.432410 -0.927566 0.000000 1.000000 0.000000
+4.188114 1.432409 2.826117 0.000000 1.000000 0.000000

+ 13 - 0
test/unit/utObjImportExport.cpp

@@ -354,3 +354,16 @@ TEST_F(utObjImportExport, 0based_array_Test) {
     const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), 0);
     EXPECT_EQ(nullptr, scene);
 }
+
+TEST_F( utObjImportExport, mtllib_after_g ) {
+    ::Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/cube_mtllib_after_g.obj", aiProcess_ValidateDataStructure );
+    ASSERT_NE( nullptr, scene );
+
+    EXPECT_EQ(scene->mNumMeshes, 1U);
+    const aiMesh *mesh = scene->mMeshes[0];
+    const aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
+    aiString name;
+    ASSERT_EQ(aiReturn_SUCCESS, mat->Get(AI_MATKEY_NAME, name));
+    EXPECT_STREQ("MyMaterial", name.C_Str());
+}

+ 55 - 6
test/unit/utPLYImportExport.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Exporter.hpp>
 #include <assimp/scene.h>
 #include "AbstractImportExportBase.h"
+#include <assimp/postprocess.h>
 
 using namespace ::Assimp;
 
@@ -52,7 +53,7 @@ class utPLYImportExport : public AbstractImportExportBase {
 public:
     virtual bool importerTest() {
         Assimp::Importer importer;
-        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0 );
+        const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure);
         EXPECT_EQ( 1u, scene->mNumMeshes );
         EXPECT_NE( nullptr, scene->mMeshes[0] );
         EXPECT_EQ( 8u, scene->mMeshes[0]->mNumVertices );
@@ -65,7 +66,7 @@ public:
     virtual bool exporterTest() {
         Importer importer;
         Exporter exporter;
-        const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0);
+        const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure);
         EXPECT_NE(nullptr, scene);
         EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_test.ply"));
 
@@ -89,19 +90,66 @@ TEST_F(utPLYImportExport, exportTest_Success ) {
 //Test issue 1623, crash when loading two PLY files in a row
 TEST_F(utPLYImportExport, importerMultipleTest) {
     Assimp::Importer importer;
-    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0);
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure);
 
     EXPECT_NE(nullptr, scene);
 
-    scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0);
+    scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure);
 
     EXPECT_NE(nullptr, scene);
+    EXPECT_NE(nullptr, scene->mMeshes[0]);
+    EXPECT_EQ(6u, scene->mMeshes[0]->mNumFaces);
+}
+
+TEST_F(utPLYImportExport, importPLYwithUV) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube_uv.ply", aiProcess_ValidateDataStructure);
+
+    EXPECT_NE(nullptr, scene);
+    EXPECT_NE(nullptr, scene->mMeshes[0]);
+    //This test model is using n-gons, so 6 faces instead of 12 tris
+    EXPECT_EQ(6u, scene->mMeshes[0]->mNumFaces);
+    EXPECT_EQ(aiPrimitiveType_POLYGON, scene->mMeshes[0]->mPrimitiveTypes);
+    EXPECT_EQ(true, scene->mMeshes[0]->HasTextureCoords(0));
+}
+
+TEST_F(utPLYImportExport, importBinaryPLY) {
+    Assimp::Importer importer;
+    const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube_binary.ply", aiProcess_ValidateDataStructure);
+
+    EXPECT_NE(nullptr, scene);
+    EXPECT_NE(nullptr, scene->mMeshes[0]);
+    //This test model is double sided, so 12 faces instead of 6
+    EXPECT_EQ(12u, scene->mMeshes[0]->mNumFaces);
 }
 
 TEST_F( utPLYImportExport, vertexColorTest ) {
     Assimp::Importer importer;
-    const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/float-color.ply", 0 );
+    const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/float-color.ply", aiProcess_ValidateDataStructure);
     EXPECT_NE( nullptr, scene );
+    EXPECT_EQ(1u, scene->mMeshes[0]->mNumFaces);
+    EXPECT_EQ(aiPrimitiveType_TRIANGLE, scene->mMeshes[0]->mPrimitiveTypes);
+    EXPECT_EQ(true, scene->mMeshes[0]->HasVertexColors(0));
+
+    auto first_face = scene->mMeshes[0]->mFaces[0];
+    EXPECT_EQ(3, first_face.mNumIndices);
+    EXPECT_EQ(0, first_face.mIndices[0]);
+    EXPECT_EQ(1, first_face.mIndices[1]);
+    EXPECT_EQ(2, first_face.mIndices[2]);
+}
+
+//Test issue #623, PLY importer should not automatically create faces
+TEST_F(utPLYImportExport, pointcloudTest) {
+  Assimp::Importer importer;
+  //Could not use aiProcess_ValidateDataStructure since it's missing faces.
+  const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/issue623.ply", 0);
+  EXPECT_NE(nullptr, scene);
+
+  EXPECT_EQ(1u, scene->mNumMeshes);
+  EXPECT_NE(nullptr, scene->mMeshes[0]);
+  EXPECT_EQ(24u, scene->mMeshes[0]->mNumVertices);
+  EXPECT_EQ(aiPrimitiveType::aiPrimitiveType_POINT, scene->mMeshes[0]->mPrimitiveTypes);
+  EXPECT_EQ(0u, scene->mMeshes[0]->mNumFaces);
 }
 
 static const char *test_file =
@@ -125,6 +173,7 @@ static const char *test_file =
 
 TEST_F( utPLYImportExport, parseErrorTest ) {
     Assimp::Importer importer;
-    const aiScene *scene = importer.ReadFileFromMemory( test_file, strlen( test_file ), 0 );
+    //Could not use aiProcess_ValidateDataStructure since it's missing faces.
+    const aiScene *scene = importer.ReadFileFromMemory( test_file, strlen( test_file ), 0);
     EXPECT_NE( nullptr, scene );
 }

+ 26 - 0
tools/assimp_cmd/Info.cpp

@@ -329,6 +329,29 @@ int Assimp_Info (const char* const* params, unsigned int num)
 		special_points[2][0],special_points[2][1],special_points[2][2]
 		)
 	;
+
+	// meshes
+	if (scene->mNumMeshes) {
+		printf("\nMeshes:  (name) [vertices / bones / faces | primitive_types]\n");
+	}
+	for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
+		const aiMesh* mesh = scene->mMeshes[i];
+		printf("    %d (%s)", i, mesh->mName.C_Str());
+		printf(
+			": [%d / %d / %d |",
+			mesh->mNumVertices,
+			mesh->mNumBones,
+			mesh->mNumFaces
+		);
+		const unsigned int ptypes = mesh->mPrimitiveTypes;
+		if (ptypes & aiPrimitiveType_POINT) { printf(" point"); }
+		if (ptypes & aiPrimitiveType_LINE) { printf(" line"); }
+		if (ptypes & aiPrimitiveType_TRIANGLE) { printf(" triangle"); }
+		if (ptypes & aiPrimitiveType_POLYGON) { printf(" polygon"); }
+		printf("]\n");
+	}
+
+	// materials
 	unsigned int total=0;
 	for(unsigned int i = 0;i < scene->mNumMaterials; ++i) {
 		aiString name;
@@ -340,6 +363,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
 		printf("\n");
 	}
 
+	// textures
 	total=0;
 	for(unsigned int i = 0;i < scene->mNumMaterials; ++i) {
 		aiString name;
@@ -369,6 +393,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
 		printf("\n");
 	}
 
+	// animations
 	total=0;
 	for(unsigned int i = 0;i < scene->mNumAnimations; ++i) {
 		if (scene->mAnimations[i]->mName.length) {
@@ -379,6 +404,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
 		printf("\n");
 	}
 
+	// node hierarchy
 	printf("\nNode hierarchy:\n");
 	unsigned int cline=0;
 	PrintHierarchy(scene->mRootNode,20,1000,cline,verbose);