public static void RecursiveBackwardsAddObject(Transform transform)
        {
            SceneTrackObject obj = transform.GetComponent <SceneTrackObject>();

            if (obj == null)
            {
                obj = transform.gameObject.AddComponent <SceneTrackObject>();
            }

            Transform parent = transform.parent;

            if (parent != null)
            {
                RecursiveBackwardsAddObject(parent);
            }
        }
        public static void RecursiveBackwardsAddObjectAndInitialise(Transform transform)
        {
            SceneTrackObject obj = transform.GetComponent <SceneTrackObject>();

            if (obj == null)
            {
                obj = transform.gameObject.AddComponent <SceneTrackObject>();
            }

            if (obj.IsInitializedOrInitializing == false)
            {
                obj.Init();
            }

            Transform parent = transform.parent;

            if (parent != null)
            {
                RecursiveBackwardsAddObjectAndInitialise(parent);
            }
        }
        private void RecordPhysicsEvent(Classes.PhysicsEvent.EventType eventType, Vector3 worldLocation, float intensity = 0, SceneTrackObject other = null)
        {
            _physicsEventHandle = Object.CreateObject(Classes.PhysicsEvent.Type);

            Object.SetValue_uint8(_physicsEventHandle, Classes.PhysicsEvent.Event, (byte)eventType);
            Object.SetValue_3_float32(_physicsEventHandle, Classes.PhysicsEvent.ContactPoint, worldLocation.x, worldLocation.y, worldLocation.z);
            Object.SetValue_float32(_physicsEventHandle, Classes.PhysicsEvent.Strength, intensity);

            Object.SetValue_2_uint32(_physicsEventHandle, Classes.PhysicsEvent.RelationReference, _handle,
                                     other != null ? other.GameObjectHandle : 0);

            // Helper.SubmitString(_physicsEventHandle, Classes.PhysicsEvent.UserData, UserDefinedData);
        }
        /// <summary>
        /// Record Transform Changes
        /// </summary>
        /// <param name="forceUpdate">Force the data to be sent to SceneTrack</param>
        private void RecordTransform(bool forceUpdate = false)
        {
            if (overridePose)
            {
                forceUpdate = true;
            }

            // No need to update
            if (!forceUpdate && !_transform.hasChanged && !(_transform.parent != _transformParent))
            {
                return;
            }

            // Check our parent, and reassign and setup it if necessary in SceneTrack
            if (_transform.parent != _transformParent)
            {
                // If we have no parent, make sure to set the handle to 0
                if (_transform.parent == null)
                {
                    _transformParentHandle = 0;
                }
                else
                {
                    // Check if we have a SceneTrackObject on the new parent, if we don't add one
                    _parentSceneTrackObject = _transform.parent.GetComponent <SceneTrackObject>() ??
                                              _transform.parent.gameObject.AddComponent <SceneTrackObject>();

                    // TODO: Possibly add forced init of parent if the order is wrong
                    // ADDED BY ROBIN: Looks like this does happen. Children get initialised before parents.
                    if (_parentSceneTrackObject._initialized == false)
                    {
                        _parentSceneTrackObject.Init();
                    }

                    // Setup some cached references
                    _transformParentHandle = _parentSceneTrackObject.TransformHandle;
                    _transformParent       = _transform.parent;
                }

                // Assign our transform handle inside of SceneTrack as it will have changed
                Object.SetValue_uint32(TransformHandle, Classes.Transform.Parent, _transformParentHandle);
            }

            Vector3    localP, localS;
            Quaternion localR;

            if (overridePose)
            {
                overridePose = false;
                localP       = overridePosePosition;
                localR       = overridePoseRotation;
                localS       = overridePoseScale;
            }
            else
            {
                localP = _transform.localPosition;
                localR = _transform.localRotation;
                localS = _transform.localScale;
            }

            // Update Transform Position, Rotation and Scale.
            Object.SetValue_3_float32(TransformHandle, Classes.Transform.LocalPosition, localP.x, localP.y, localP.z);
            Object.SetValue_4_float32(TransformHandle, Classes.Transform.LocalRotation, localR.x, localR.y, localR.z, localR.w);
            Object.SetValue_3_float32(TransformHandle, Classes.Transform.LocalScale, localS.x, localS.y, localS.z);
        }
        /// <summary>
        /// Initialize SceenTrack MeshFilter/MeshRenderer Component
        /// </summary>
        private void InitMeshRenderer()
        {
            // Cache references
            _meshFilter          = GetComponent <MeshFilter>();
            _meshRenderer        = GetComponent <MeshRenderer>();
            _skinnedMeshRenderer = GetComponent <SkinnedMeshRenderer>();

            // Determine if we need to use the SkinnedMeshRenderer Logic
            IsSkinned = _skinnedMeshRenderer != null;

            // Create Materials
            InitMaterials(IsSkinned ? _skinnedMeshRenderer.sharedMaterials : _meshRenderer.sharedMaterials);

            // Create Mesh
            Mesh mesh = null;

            if (overrideMeshMesh != null)
            {
                mesh = overrideMeshMesh;
            }
            else
            {
                if (_skinnedMeshRenderer != null)
                {
                    mesh = _skinnedMeshRenderer.sharedMesh;
                }
                else if (_meshFilter != null)
                {
                    mesh = _meshFilter.sharedMesh;
                }
            }

            var foundMesh = InitMesh(mesh);

            if (foundMesh == false)
            {
                TrackMeshRenderer = false;

                if (_skinnedMeshRenderer != null)
                {
                    global::UnityEngine.Debug.LogWarningFormat("[SceneTrack] No mesh attached to Skinned Mesh Renderer '{0}'. Recording will be affected.");
                }
                else if (_meshFilter != null)
                {
                    global::UnityEngine.Debug.LogWarningFormat("[SceneTrack] No mesh attached Mesh Filter '{0}'. Recording will be affected.");
                }

                return;
            }

            // Create Renderer
            if (IsSkinned && _skinnedMeshRenderer != null)
            {
                _skinnedMeshRendererHandle = SceneTrack.Object.CreateObject(Classes.SkinnedMeshRenderer.Type);

                // Assign Mesh (shared reference if found) to MeshRenderer
                Object.SetValue_uint32(_skinnedMeshRendererHandle, Classes.SkinnedMeshRenderer.Mesh, _meshHandle);

                // Assign Parent (transform) , Duplication Understood.
                Object.SetValue_uint32(_skinnedMeshRendererHandle, Classes.SkinnedMeshRenderer.Parent, TransformHandle);

                // Assign Materials (shared references as found)
                Helper.SubmitArray(_skinnedMeshRendererHandle, Classes.SkinnedMeshRenderer.Materials, _materialHandles, Helper.GetTypeMemorySize(typeof(uint), 1));

                // Assign Bone Transform (Root Object)
                // Check if we have a SceneTrackObject on the bone root, if we don't add one
                // TODO: Robin/Matthew
                //  Check to see if this is true. I've seen RootBones that aren't a direct child of the SkinnedMeshRenderer.

                if (_skinnedMeshRenderer.rootBone != null)
                {
                    _boneRootObject = _skinnedMeshRenderer.rootBone.GetComponent <SceneTrackObject>() ??
                                      _skinnedMeshRenderer.rootBone.gameObject.AddComponent <SceneTrackObject>();
                    Object.SetValue_uint32(_skinnedMeshRendererHandle, Classes.SkinnedMeshRenderer.BoneTransform, _boneRootObject.TransformHandle);
                }
                else
                {
                    Debug.LogErrorFormat("[SceneTrack] Root Bone Missing for {0}", name);
                }

                // Assign Bones
                Transform[] cachedBones      = _skinnedMeshRenderer.bones;
                int         cachedBonesCount = cachedBones.Length;

                uint[] boneHandles = new uint[cachedBones.Length];

                for (int i = 0; i < cachedBonesCount; i++)
                {
                    Helper.RecursiveBackwardsAddObjectAndInitialise(cachedBones[i]);
                    SceneTrackObject boneObject = cachedBones[i].GetComponent <SceneTrackObject>();
                    boneHandles[i] = boneObject.TransformHandle;
                }

                Helper.SubmitArray(_skinnedMeshRendererHandle, Classes.SkinnedMeshRenderer.Bones, boneHandles, Helper.GetTypeMemorySize(typeof(uint), 1));

                // BoneTransform.  Assumed to be the parent of the Root Bone.
                Transform rootBone = _skinnedMeshRenderer.rootBone;

                if (rootBone != null)
                {
                    Transform rootBoneParent = rootBone.parent;
                    if (rootBoneParent != null)
                    {
                        Helper.RecursiveBackwardsAddObjectAndInitialise(rootBoneParent);

                        SceneTrackObject rootBoneParentObject = rootBoneParent.GetComponent <SceneTrackObject>();

                        SceneTrack.Object.SetValue_uint32(_skinnedMeshRendererHandle, Classes.SkinnedMeshRenderer.BoneTransform, rootBoneParentObject.TransformHandle);
                    }
                }
            }
            else if (_meshFilter != null)
            {
                _meshRendererHandle = SceneTrack.Object.CreateObject(Classes.StandardMeshRenderer.Type);

                // Assign Mesh (shared reference if found) to MeshRenderer
                Object.SetValue_uint32(_meshRendererHandle, Classes.StandardMeshRenderer.Mesh, _meshHandle);

                // Assign Parent (transform) , Duplication Understood.
                Object.SetValue_uint32(_meshRendererHandle, Classes.StandardMeshRenderer.Parent, TransformHandle);

                // Assign Materials (shared references as found)
                if (_materialHandles.Length > 0)
                {
                    Helper.SubmitArray(_meshRendererHandle, Classes.StandardMeshRenderer.Materials, _materialHandles, Helper.GetTypeMemorySize(typeof(uint), 1));
                }
            }
        }