protected void CheckAnimCurve(
            FbxObject origAnimObject, FbxObject importAnimObject,
            FbxAnimLayer origLayer, FbxAnimLayer importLayer,
            List <PropertyComponentPair> propCompPairs,
            FbxNodeAttribute origNodeAttr = null, FbxNodeAttribute importNodeAttr = null)
        {
            foreach (var pair in propCompPairs)
            {
                FbxProperty origProperty = origAnimObject.FindProperty(pair.propertyName, false);
                if (origNodeAttr != null && (origProperty == null || !origProperty.IsValid()))
                {
                    origProperty = origNodeAttr.FindProperty(pair.propertyName, false);
                }
                FbxProperty importProperty = importAnimObject.FindProperty(pair.propertyName, false);
                if (importNodeAttr != null && (importProperty == null || !importProperty.IsValid()))
                {
                    importProperty = importNodeAttr.FindProperty(pair.propertyName, false);
                }

                Assert.IsNotNull(origProperty);
                Assert.IsNotNull(importProperty);
                Assert.IsTrue(origProperty.IsValid());
                Assert.IsTrue(importProperty.IsValid());

                foreach (var component in pair.componentList)
                {
                    FbxAnimCurve origAnimCurve   = origProperty.GetCurve(origLayer, component, false);
                    FbxAnimCurve importAnimCurve = importProperty.GetCurve(importLayer, component, false);

                    Assert.IsNotNull(origAnimCurve);
                    Assert.IsNotNull(importAnimCurve);

                    Assert.AreEqual(origAnimCurve.KeyGetCount(), importAnimCurve.KeyGetCount());

                    for (int i = 0; i < origAnimCurve.KeyGetCount(); i++)
                    {
                        Assert.AreEqual(origAnimCurve.KeyGetTime(i), importAnimCurve.KeyGetTime(i));
                        Assert.AreEqual(origAnimCurve.KeyGetValue(i), importAnimCurve.KeyGetValue(i));
                    }
                }
            }
        }
        protected void CreateAnimCurves(
            FbxObject animObject, FbxAnimLayer animLayer,
            List <PropertyComponentPair> properties,
            System.Func <int, double> calcTime, // lambda function for calculating time based on index
            System.Func <int, float> calcValue, // lambda function for calculating value based on index
            FbxNodeAttribute animNodeAttr = null)
        {
            foreach (var pair in properties)
            {
                FbxProperty fbxProperty = animObject.FindProperty(pair.propertyName, false);
                if (animNodeAttr != null && (fbxProperty == null || !fbxProperty.IsValid()))
                {
                    // backup method for finding the property if we can't find it on the node itself
                    fbxProperty = animNodeAttr.FindProperty(pair.propertyName, false);
                }

                Assert.IsNotNull(fbxProperty);
                Assert.IsTrue(fbxProperty.IsValid());
                Assert.That(fbxProperty.GetFlag(FbxPropertyFlags.EFlags.eAnimatable), Is.True);

                foreach (var component in pair.componentList)
                {
                    // Create the AnimCurve on the channel
                    FbxAnimCurve fbxAnimCurve = fbxProperty.GetCurve(animLayer, component, true);

                    Assert.IsNotNull(fbxAnimCurve);

                    fbxAnimCurve.KeyModifyBegin();
                    for (int keyIndex = 0; keyIndex < m_keyCount; ++keyIndex)
                    {
                        FbxTime fbxTime = FbxTime.FromSecondDouble(calcTime(keyIndex));
                        fbxAnimCurve.KeyAdd(fbxTime);
                        fbxAnimCurve.KeySet(keyIndex, fbxTime, calcValue(keyIndex));
                    }
                    fbxAnimCurve.KeyModifyEnd();
                }
            }
        }
        protected void CheckCameraSettings(FbxCamera origCamera, FbxCamera importCamera, FbxNode origCameraNode, FbxNode importCameraNode)
        {
            Assert.AreEqual(origCamera.ProjectionType.Get(), importCamera.ProjectionType.Get());
            Assert.AreEqual(origCamera.AspectWidth.Get(), importCamera.AspectWidth.Get());
            Assert.AreEqual(origCamera.AspectHeight.Get(), importCamera.AspectHeight.Get());
            Assert.AreEqual(origCamera.GetAspectRatioMode(), importCamera.GetAspectRatioMode());
            Assert.AreEqual(origCamera.FilmAspectRatio.Get(), importCamera.FilmAspectRatio.Get());
            Assert.AreEqual(origCamera.GetApertureWidth(), importCamera.GetApertureWidth());
            Assert.AreEqual(origCamera.GetApertureHeight(), importCamera.GetApertureHeight());
            Assert.AreEqual(origCamera.GetApertureMode(), origCamera.GetApertureMode());
            Assert.AreEqual(origCamera.FocalLength.Get(), importCamera.FocalLength.Get());
            Assert.AreEqual(origCamera.GetNearPlane(), importCamera.GetNearPlane());
            Assert.AreEqual(origCamera.GetFarPlane(), importCamera.GetFarPlane());

            foreach (var customProp in new string[] { "backgroundColor", "clearFlags" })
            {
                FbxProperty property = origCameraNode.FindProperty(customProp);
                Assert.IsNotNull(property);
                Assert.IsTrue(property.IsValid());

                FbxProperty importBgColorProp = importCameraNode.FindProperty(customProp);
                Assert.IsNotNull(importBgColorProp);
                Assert.IsTrue(importBgColorProp.IsValid());

                if (property.GetPropertyDataType().Equals(Globals.FbxColor4DT))
                {
                    Assert.AreEqual(property.GetFbxColor(), property.GetFbxColor());
                }
                else if (property.GetPropertyDataType().Equals(Globals.FbxIntDT))
                {
                    Assert.AreEqual(property.GetInt(), property.GetInt());
                }

                Assert.AreEqual(property.GetFlag(FbxPropertyFlags.EFlags.eUserDefined),
                                importBgColorProp.GetFlag(FbxPropertyFlags.EFlags.eUserDefined));
                Assert.AreEqual(property.GetFlag(FbxPropertyFlags.EFlags.eAnimatable),
                                importBgColorProp.GetFlag(FbxPropertyFlags.EFlags.eAnimatable));
            }
        }
        protected override void CheckScene(FbxScene scene)
        {
            base.CheckScene(scene);

            FbxScene origScene = CreateScene(FbxManager);

            Assert.IsNotNull(origScene);

            // Retrieve the mesh from each scene
            FbxMesh origMesh   = origScene.GetRootNode().GetChild(0).GetMesh();
            FbxMesh importMesh = scene.GetRootNode().GetChild(0).GetMesh();

            // get the layers
            FbxLayer origLayer   = origMesh.GetLayer(0 /* default layer */);
            FbxLayer importLayer = importMesh.GetLayer(0 /* default layer */);

            // Check UVs
            var origUVElement   = origLayer.GetUVs();
            var importUVElement = importLayer.GetUVs();

            Assert.AreEqual(origUVElement.GetMappingMode(), importUVElement.GetMappingMode());
            Assert.AreEqual(origUVElement.GetReferenceMode(), importUVElement.GetReferenceMode());

            var origUVElementArray   = origUVElement.GetDirectArray();
            var importUVElementArray = importUVElement.GetDirectArray();

            Assert.AreEqual(origUVElementArray.GetCount(), importUVElementArray.GetCount());

            for (int i = 0; i < origUVElementArray.GetCount(); i++)
            {
                Assert.AreEqual(origUVElementArray.GetAt(i), importUVElementArray.GetAt(i));
            }

            var origUVElementIndex   = origUVElement.GetIndexArray();
            var importUVElementIndex = origUVElement.GetIndexArray();

            Assert.AreEqual(origUVElementIndex.GetCount(), importUVElementIndex.GetCount());

            for (int i = 0; i < origUVElementIndex.GetCount(); i++)
            {
                Assert.AreEqual(origUVElementIndex.GetAt(i), importUVElementIndex.GetAt(i));
            }

            // Check material and texture
            var origNode     = origScene.GetRootNode().GetChild(0);
            int origMatIndex = origNode.GetMaterialIndex(m_materialName);

            Assert.GreaterOrEqual(origMatIndex, 0);
            var origMaterial = origNode.GetMaterial(origMatIndex);

            Assert.IsNotNull(origMaterial);

            var importNode     = scene.GetRootNode().GetChild(0);
            int importMatIndex = importNode.GetMaterialIndex(m_materialName);

            Assert.GreaterOrEqual(importMatIndex, 0);
            var importMaterial = importNode.GetMaterial(importMatIndex);

            Assert.IsNotNull(importMaterial);

            // TODO: Add ability to Downcast the material to an FbxSurfacePhong.
            Property[] materialProperties =
            {
                new Property(FbxSurfaceMaterial.sDiffuse,    PropertyType.Color),
                new Property(FbxSurfaceMaterial.sEmissive,   PropertyType.Color),
                new Property(FbxSurfaceMaterial.sAmbient,    PropertyType.Double3),
                new Property(FbxSurfaceMaterial.sSpecular,   PropertyType.Double3),
                new Property(FbxSurfaceMaterial.sBumpFactor, PropertyType.Double)
            };

            FbxProperty origMaterialDiffuseProperty   = null;
            FbxProperty importMaterialDiffuseProperty = null;

            foreach (var prop in materialProperties)
            {
                FbxProperty origProp = origMaterial.FindProperty(prop.name);
                Assert.IsNotNull(origProp);
                Assert.IsTrue(origProp.IsValid());

                FbxProperty importProp = importMaterial.FindProperty(prop.name);
                Assert.IsNotNull(importProp);
                Assert.IsTrue(importProp.IsValid());

                switch (prop.type)
                {
                case PropertyType.Color:
                    Assert.AreEqual(origProp.GetFbxColor(), importProp.GetFbxColor());
                    break;

                case PropertyType.Double3:
                    Assert.AreEqual(origProp.GetFbxDouble3(), importProp.GetFbxDouble3());
                    break;

                case PropertyType.Double:
                    Assert.AreEqual(origProp.GetDouble(), importProp.GetDouble());
                    break;

                default:
                    break;
                }

                if (prop.name.Equals(FbxSurfaceMaterial.sDiffuse))
                {
                    origMaterialDiffuseProperty   = origProp;
                    importMaterialDiffuseProperty = importProp;
                }
            }

            Assert.IsNotNull(origMaterialDiffuseProperty);
            Assert.IsNotNull(importMaterialDiffuseProperty);

            var origTexture = origMaterialDiffuseProperty.FindSrcObject(FbxSurfaceMaterial.sDiffuse + "_Texture");

            Assert.IsNotNull(origTexture);
            var importTexture = importMaterialDiffuseProperty.FindSrcObject(FbxSurfaceMaterial.sDiffuse + "_Texture");

            Assert.IsNotNull(importTexture);

            // TODO: Trying to Downcast the texture to an FbxFileTexture returns a null value,
            //       need to figure out how to fix this so we can access the texture properties.

            /*Assert.AreEqual (origTexture.GetFileName (), importTexture.GetFileName ());
             * Assert.AreEqual (origTexture.GetTextureUse (), importTexture.GetTextureUse ());
             * Assert.AreEqual (origTexture.GetMappingType (), importTexture.GetMappingType ());*/
        }
            /// <summary>
            /// Export an AnimationCurve.
            ///
            /// This is not used for rotations, because we need to convert from
            /// quaternion to euler and various other stuff.
            /// </summary>
            protected void ExportAnimCurve(UnityEngine.Object unityObj,
                                           AnimationCurve unityAnimCurve,
                                           string unityPropertyName,
                                           FbxAnimLayer fbxAnimLayer)
            {
                FbxPropertyChannelPair fbxPair;

                if (!MapUnityPropertyNameToFbx.TryGetValue(unityPropertyName, out fbxPair))
                {
                    Debug.LogWarning(string.Format("no property-channel mapping found for {0}", unityPropertyName));
                    return;
                }

                GameObject unityGo = GetGameObject(unityObj);

                if (unityGo == null)
                {
                    Debug.LogError(string.Format("cannot convert to GameObject from {0}", unityObj.ToString()));
                    return;
                }

                FbxNode fbxNode;

                if (!MapUnityObjectToFbxNode.TryGetValue(unityGo, out fbxNode))
                {
                    Debug.LogError(string.Format("cannot find fbxNode for {0}", unityGo.ToString()));
                    return;
                }

                FbxProperty fbxProperty = null;

                // try finding unity property name on node attribute
                FbxNodeAttribute fbxNodeAttribute = fbxNode.GetNodeAttribute();

                if (fbxNodeAttribute != null)
                {
                    fbxProperty = fbxNodeAttribute.FindProperty(fbxPair.Property, false);
                }

                // try finding unity property on the node
                if (fbxProperty == null || !fbxProperty.IsValid())
                {
                    fbxProperty = fbxNode.FindProperty(fbxPair.Property, false);
                }

                if (fbxProperty == null || !fbxProperty.IsValid())
                {
                    Debug.LogError(string.Format("cannot find fbxProperty {0} on {1}", fbxPair.Property, fbxNode.GetName()));
                    return;
                }

                if (Verbose)
                {
                    Debug.Log(string.Format("Exporting animation for {0} ({1})",
                                            unityObj.ToString(),
                                            fbxPair.Property));
                }

                // Create the AnimCurve on the channel
                FbxAnimCurve fbxAnimCurve = (fbxPair.Channel != null)
                    ? fbxProperty.GetCurve(fbxAnimLayer, fbxPair.Channel, true)
                                 : fbxProperty.GetCurve(fbxAnimLayer, true);

                // copy Unity AnimCurve to FBX AnimCurve.
                fbxAnimCurve.KeyModifyBegin();

                for (int keyIndex = 0, n = unityAnimCurve.length; keyIndex < n; ++keyIndex)
                {
                    var key     = unityAnimCurve [keyIndex];
                    var fbxTime = FbxTime.FromSecondDouble(key.time);
                    fbxAnimCurve.KeyAdd(fbxTime);
                    fbxAnimCurve.KeySet(keyIndex, fbxTime, key.value);
                }

                fbxAnimCurve.KeyModifyEnd();
            }