Browse Source

Merge branch 'master' into ios-build-script

* master:
  LWOMaterial: Fix strict aliasing violations
  3DS: Fix strict aliasing violations
  Fix strict aliasing violation in MaterialSystem
  Replace type punning with explicit memcpys
  Update FBXConverter.cpp
  Update Readme.md
  FBX: LayeredTextures now work with embedded texture data
  [pyassimp] README.{md->rst} to please distutils. Bumped to 4.1.3
  [pyassimp] Updated setup.py
  Properly reads in glTF/2.0 sampler address modes.
  does not access undefined memory area anymore.
Doron Adler 7 years ago
parent
commit
d86a0e3adb

+ 5 - 3
code/3DSConverter.cpp

@@ -204,8 +204,9 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
         mat.AddProperty<ai_real>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
 
     // Setup the texture mapping mode
-    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
-    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
+    int mapMode = static_cast<int>(texture.mMapMode);
+    mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
+    mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
 
     // Mirroring - double the scaling values
     // FIXME: this is not really correct ...
@@ -313,7 +314,8 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
         case D3DS::Discreet3DS::Blinn :
             eShading = aiShadingMode_Blinn; break;
     }
-    mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
+    int eShading_ = static_cast<int>(eShading);
+    mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
 
     // DIFFUSE texture
     if( oldMat.sTexDiffuse.mMapName.length() > 0)

+ 42 - 38
code/FBXConverter.cpp

@@ -1526,6 +1526,46 @@ unsigned int Converter::ConvertVideo( const Video& video )
     return static_cast<unsigned int>( textures.size() - 1 );
 }
 
+aiString Converter::GetTexturePath(const Texture* tex)
+{
+    aiString path;
+    path.Set(tex->RelativeFilename());
+
+    const Video* media = tex->Media();
+    if (media != nullptr) {
+        bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
+        unsigned int index;
+
+        VideoMap::const_iterator it = textures_converted.find(media);
+        if (it != textures_converted.end()) {
+            index = (*it).second;
+            textureReady = true;
+        }
+        else {
+            if (media->ContentLength() > 0) {
+                index = ConvertVideo(*media);
+                textures_converted[media] = index;
+                textureReady = true;
+            }
+        }
+
+        // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
+        if (doc.Settings().useLegacyEmbeddedTextureNaming) {
+            if (textureReady) {
+                // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
+                // In FBX files textures are now stored internally by Assimp with their filename included
+                // Now Assimp can lookup through the loaded textures after all data is processed
+                // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
+                // This may occur on this case too, it has to be studied
+                path.data[0] = '*';
+                path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
+            }
+        }
+    }
+
+    return path;
+}
+
 void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& textures,
     const std::string& propName,
     aiTextureType target, const MeshGeometry* const mesh )
@@ -1538,41 +1578,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
     const Texture* const tex = ( *it ).second;
     if ( tex != 0 )
     {
-        aiString path;
-        path.Set( tex->RelativeFilename() );
-
-        const Video* media = tex->Media();
-        if (media != 0) {
-			bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
-			unsigned int index;
-
-			VideoMap::const_iterator it = textures_converted.find(media);
-			if (it != textures_converted.end()) {
-				index = (*it).second;
-				textureReady = true;
-			}
-			else {
-				if (media->ContentLength() > 0) {
-					index = ConvertVideo(*media);
-					textures_converted[media] = index;
-					textureReady = true;
-				}
-			}
-
-			// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
-			if (doc.Settings().useLegacyEmbeddedTextureNaming) {
-                if (textureReady) {
-                    // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
-                    // In FBX files textures are now stored internally by Assimp with their filename included
-                    // Now Assimp can lookup through the loaded textures after all data is processed
-                    // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
-                    // This may occur on this case too, it has to be studied
-                    path.data[0] = '*';
-                    path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
-                }
-			}
-		}  
-
+        aiString path = GetTexturePath(tex);
         out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 );
 
         aiUVTransform uvTrafo;
@@ -1696,9 +1702,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextu
     
         const Texture* const tex = ( *it ).second->getTexture(texIndex);
 
-        aiString path;
-        path.Set( tex->RelativeFilename() );
-
+        aiString path = GetTexturePath(tex);
         out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, texIndex );
 
         aiUVTransform uvTrafo;

+ 4 - 0
code/FBXConverter.h

@@ -228,6 +228,10 @@ private:
     // Video -> aiTexture
     unsigned int ConvertVideo(const Video& video);
 
+    // ------------------------------------------------------------------------------------------------
+    // convert embedded texture if necessary and return actual texture path
+    aiString GetTexturePath(const Texture* tex);
+
     // ------------------------------------------------------------------------------------------------
     void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
         const std::string& propName,

+ 4 - 2
code/LWOMaterial.cpp

@@ -253,7 +253,8 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
         pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
 
         // setup the mapping mode
-        pcMat->AddProperty<int>((int*)&mapping,1,AI_MATKEY_MAPPING(type,cur));
+        int mapping_ = static_cast<int>(mapping);
+        pcMat->AddProperty<int>(&mapping_, 1, AI_MATKEY_MAPPING(type, cur));
 
         // add the u-wrapping
         temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
@@ -365,7 +366,8 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
     }
     if (surf.mMaximumSmoothAngle <= 0.0)
         m = aiShadingMode_Flat;
-    pcMat->AddProperty((int*)&m,1,AI_MATKEY_SHADING_MODEL);
+    int m_ = static_cast<int>(m);
+    pcMat->AddProperty(&m_, 1, AI_MATKEY_SHADING_MODEL);
 
     // (the diffuse value is just a scaling factor)
     // If a diffuse texture is set, we set this value to 1.0

+ 3 - 2
code/MaterialSystem.cpp

@@ -354,8 +354,9 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
         return AI_FAILURE;
     }
     // Determine mapping type
-    aiTextureMapping mapping = aiTextureMapping_UV;
-    aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index),(int*)&mapping);
+    int mapping_ = static_cast<int>(aiTextureMapping_UV);
+    aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index), &mapping_);
+    aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
     if (_mapping)
         *_mapping = mapping;
 

+ 2 - 2
code/STLLoader.cpp

@@ -365,10 +365,10 @@ void STLImporter::LoadASCIIFile( aiNode *root ) {
         pMesh->mNumFaces = static_cast<unsigned int>(positionBuffer.size() / 3);
         pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
         pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
-        memcpy(pMesh->mVertices, &positionBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+        memcpy(pMesh->mVertices, positionBuffer.data(), pMesh->mNumVertices * sizeof(aiVector3D));
         positionBuffer.clear();
         pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
-        memcpy(pMesh->mNormals, &normalBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+        memcpy(pMesh->mNormals, normalBuffer.data(), pMesh->mNumVertices * sizeof(aiVector3D));
         normalBuffer.clear();
 
         // now copy faces

+ 19 - 2
code/glTF2Importer.cpp

@@ -121,6 +121,21 @@ bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool
     return false;
 }
 
+static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode)
+{
+    switch (gltfWrapMode) {
+        case SamplerWrap::Mirrored_Repeat:
+            return aiTextureMapMode_Mirror;
+
+        case SamplerWrap::Clamp_To_Edge:
+            return aiTextureMapMode_Clamp;
+
+        case SamplerWrap::UNSET:
+        case SamplerWrap::Repeat:
+        default:
+            return aiTextureMapMode_Wrap;
+    }
+}
 
 //static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
 //{
@@ -198,8 +213,10 @@ inline void SetMaterialTextureProperty(std::vector<int>& embeddedTexIdxs, Asset&
             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));
+            aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS);
+            aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT);
+            mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
+            mat->AddProperty(&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));

+ 14 - 6
include/assimp/qnan.h

@@ -98,8 +98,10 @@ AI_FORCE_INLINE bool is_qnan(float in)
     //   compare <register-with-different-width> against <in>
 
     // FIXME: Use <float> stuff instead? I think fpclassify needs C99
-    return (reinterpret_cast<_IEEESingle*>(&in)->IEEE.Exp == (1u << 8)-1 &&
-        reinterpret_cast<_IEEESingle*>(&in)->IEEE.Frac);
+    _IEEESingle temp;
+    memcpy(&temp, &in, sizeof(float));
+    return (temp.IEEE.Exp == (1u << 8)-1 &&
+        temp.IEEE.Frac);
 }
 
 // ---------------------------------------------------------------------------
@@ -114,8 +116,10 @@ AI_FORCE_INLINE bool is_qnan(double in)
     //   compare <register-with-different-width> against <in>
 
     // FIXME: Use <float> stuff instead? I think fpclassify needs C99
-    return (reinterpret_cast<_IEEEDouble*>(&in)->IEEE.Exp == (1u << 11)-1 &&
-        reinterpret_cast<_IEEEDouble*>(&in)->IEEE.Frac);
+    _IEEEDouble temp;
+    memcpy(&temp, &in, sizeof(in));
+    return (temp.IEEE.Exp == (1u << 11)-1 &&
+        temp.IEEE.Frac);
 }
 
 // ---------------------------------------------------------------------------
@@ -125,7 +129,9 @@ AI_FORCE_INLINE bool is_qnan(double in)
  *  @param in Input value */
 AI_FORCE_INLINE bool is_special_float(float in)
 {
-    return (reinterpret_cast<_IEEESingle*>(&in)->IEEE.Exp == (1u << 8)-1);
+    _IEEESingle temp;
+    memcpy(&temp, &in, sizeof(float));
+    return (temp.IEEE.Exp == (1u << 8)-1);
 }
 
 // ---------------------------------------------------------------------------
@@ -135,7 +141,9 @@ AI_FORCE_INLINE bool is_special_float(float in)
  *  @param in Input value */
 AI_FORCE_INLINE bool is_special_float(double in)
 {
-    return (reinterpret_cast<_IEEEDouble*>(&in)->IEEE.Exp == (1u << 11)-1);
+   _IEEESingle temp;
+    memcpy(&temp, &in, sizeof(float));
+    return (temp.IEEE.Exp == (1u << 11)-1);
 }
 
 // ---------------------------------------------------------------------------

+ 1 - 1
port/AssimpNET/Readme.md

@@ -1 +1 @@
-See https://code.google.com/p/assimp-net/ and https://github.com/assimp/assimp-net for a Github mirror.
+Please check the following github-repo for the source: https://github.com/kebby/assimp-net

+ 0 - 94
port/PyAssimp/README.md

@@ -1,94 +0,0 @@
-PyAssimp Readme
-===============
-
-A simple Python wrapper for Assimp using `ctypes` to access the library.
-Requires Python >= 2.6.
-
-Python 3 support is mostly here, but not well tested.
-
-Note that pyassimp is not complete. Many ASSIMP features are missing.
-
-USAGE
------
-
-### Complete example: 3D viewer
-
-`pyassimp` comes with a simple 3D viewer that shows how to load and display a 3D
-model using a shader-based OpenGL pipeline.
-
-![Screenshot](3d_viewer_screenshot.png)
-
-To use it, from within `/port/PyAssimp`:
-
-```
-$ cd scripts
-$ python ./3D-viewer <path to your model>
-```
-
-You can use this code as starting point in your applications.
-
-### Writing your own code
-
-To get started with `pyassimp`, examine the simpler `sample.py` script in `scripts/`,
-which illustrates the basic usage. All Assimp data structures are wrapped using
-`ctypes`. All the data+length fields in Assimp's data structures (such as
-`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python
-lists, so you can call `len()` on them to get their respective size and access
-members using `[]`.
-
-For example, to load a file named `hello.3ds` and print the first
-vertex of the first mesh, you would do (proper error handling
-substituted by assertions ...):
-
-```python
-
-from pyassimp import *
-scene = load('hello.3ds')
-
-assert len(scene.meshes)
-mesh = scene.meshes[0]
-
-assert len(mesh.vertices)
-print(mesh.vertices[0])
-
-# don't forget this one, or you will leak!
-release(scene)
-
-```
-
-Another example to list the 'top nodes' in a
-scene:
-
-```python
-
-from pyassimp import *
-scene = load('hello.3ds')
-
-for c in scene.rootnode.children:
-    print(str(c))
-
-release(scene)
-
-```
-
-INSTALL
--------
-
-Install `pyassimp` by running:
-
-```
-$ python setup.py install
-```
-
-PyAssimp requires a assimp dynamic library (`DLL` on windows,
-`.so` on linux, `.dynlib` on macOS) in order to work. The default search directories 
-are:
-
-- the current directory
-- on linux additionally: `/usr/lib`, `/usr/local/lib`,
-  `/usr/lib/x86_64-linux-gnu`
-
-To build that library, refer to the Assimp master `INSTALL`
-instructions. To look in more places, edit `./pyassimp/helper.py`.
-There's an `additional_dirs` list waiting for your entries.
-

+ 96 - 0
port/PyAssimp/README.rst

@@ -0,0 +1,96 @@
+PyAssimp: Python bindings for libassimp
+=======================================
+
+A simple Python wrapper for Assimp using ``ctypes`` to access the
+library. Requires Python >= 2.6.
+
+Python 3 support is mostly here, but not well tested.
+
+Note that pyassimp is not complete. Many ASSIMP features are missing.
+
+USAGE
+-----
+
+Complete example: 3D viewer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``pyassimp`` comes with a simple 3D viewer that shows how to load and
+display a 3D model using a shader-based OpenGL pipeline.
+
+.. figure:: 3d_viewer_screenshot.png
+   :alt: Screenshot
+
+   Screenshot
+
+To use it, from within ``/port/PyAssimp``:
+
+::
+
+    $ cd scripts
+    $ python ./3D-viewer <path to your model>
+
+You can use this code as starting point in your applications.
+
+Writing your own code
+~~~~~~~~~~~~~~~~~~~~~
+
+To get started with ``pyassimp``, examine the simpler ``sample.py``
+script in ``scripts/``, which illustrates the basic usage. All Assimp
+data structures are wrapped using ``ctypes``. All the data+length fields
+in Assimp's data structures (such as ``aiMesh::mNumVertices``,
+``aiMesh::mVertices``) are replaced by simple python lists, so you can
+call ``len()`` on them to get their respective size and access members
+using ``[]``.
+
+For example, to load a file named ``hello.3ds`` and print the first
+vertex of the first mesh, you would do (proper error handling
+substituted by assertions ...):
+
+.. code:: python
+
+
+    from pyassimp import *
+    scene = load('hello.3ds')
+
+    assert len(scene.meshes)
+    mesh = scene.meshes[0]
+
+    assert len(mesh.vertices)
+    print(mesh.vertices[0])
+
+    # don't forget this one, or you will leak!
+    release(scene)
+
+Another example to list the 'top nodes' in a scene:
+
+.. code:: python
+
+
+    from pyassimp import *
+    scene = load('hello.3ds')
+
+    for c in scene.rootnode.children:
+        print(str(c))
+
+    release(scene)
+
+INSTALL
+-------
+
+Install ``pyassimp`` by running:
+
+::
+
+    $ python setup.py install
+
+PyAssimp requires a assimp dynamic library (``DLL`` on windows, ``.so``
+on linux, ``.dynlib`` on macOS) in order to work. The default search
+directories are:
+
+-  the current directory
+-  on linux additionally: ``/usr/lib``, ``/usr/local/lib``,
+   ``/usr/lib/x86_64-linux-gnu``
+
+To build that library, refer to the Assimp master ``INSTALL``
+instructions. To look in more places, edit ``./pyassimp/helper.py``.
+There's an ``additional_dirs`` list waiting for your entries.

+ 12 - 2
port/PyAssimp/setup.py

@@ -1,15 +1,25 @@
+ #!/usr/bin/env python
  # -*- coding: utf-8 -*-
 import os
 from distutils.core import setup
 
+def readme():
+    with open('README.rst') as f:
+        return f.read()
+
 setup(name='pyassimp',
-      version='4.1.0',
+      version='4.1.3',
       license='ISC',
       description='Python bindings for the Open Asset Import Library (ASSIMP)',
+      long_description=readme(),
       url='https://github.com/assimp/assimp',
+      author='ASSIMP developers',
+      author_email='[email protected]',
+      maintainer='Séverin Lemaignan',
+      maintainer_email='[email protected]',
       packages=['pyassimp'],
       data_files=[
-                  ('share/pyassimp', ['README.md']),
+                  ('share/pyassimp', ['README.rst']),
                   ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')])
                  ],
       requires=['numpy']

+ 2 - 2
test/models/glTF2/BoxTextured-glTF/BoxTextured.gltf

@@ -146,8 +146,8 @@
         {
             "magFilter": 9729,
             "minFilter": 9986,
-            "wrapS": 10497,
-            "wrapT": 10497
+            "wrapS": 33648,
+            "wrapT": 33071
         }
     ],
     "bufferViews": [

+ 16 - 1
test/unit/utglTF2ImportExport.cpp

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Importer.hpp>
 #include <assimp/Exporter.hpp>
 #include <assimp/postprocess.h>
+#include <assimp/scene.h>
 
 using namespace Assimp;
 
@@ -54,7 +55,21 @@ public:
     virtual bool importerTest() {
         Assimp::Importer importer;
         const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
-        return nullptr != scene;
+        EXPECT_NE( scene, nullptr );
+        if ( !scene ) return false;
+
+        EXPECT_TRUE( scene->HasMaterials() );
+        if ( !scene->HasMaterials() ) return false;
+        const aiMaterial *material = scene->mMaterials[0];
+
+        aiString path;
+        aiTextureMapMode modes[2];
+        EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes) );
+        EXPECT_STREQ( path.C_Str(), "CesiumLogoFlat.png" );
+        EXPECT_EQ( modes[0], aiTextureMapMode_Mirror );
+        EXPECT_EQ( modes[1], aiTextureMapMode_Clamp );
+
+        return true;
     }
 
     virtual bool binaryImporterTest() {