void NearestVertTransfer(VPaintObjectInfo info)
    {
        var mesh = info.vpaintObject.originalMesh;

        if (!mesh)
        {
            mesh = info.vpaintObject.GetComponent <MeshFilter>().sharedMesh;
        }
        var verts    = mesh.vertices;
        var oldVerts = info.vertexCache.vertices;

        Matrix4x4 transformMatrix = Matrix4x4.TRS(vertexTransferOffset, Quaternion.Euler(vertexTransferRotate), vertexTransferScale);

        for (int i = 0; i < VPaint.Instance.layerStack.layers.Count; i++)
        {
            var layer = VPaint.Instance.layerStack.layers[i];
            var pd    = layer.Get(info.vpaintObject);
            if (pd == null)
            {
                continue;
            }
            if (pd.colors.Length == verts.Length)
            {
                continue;
            }
            var oldColors = pd.colors;
            var oldTrans  = pd.transparency;
            if (oldVerts.Length != oldColors.Length)
            {
                Debug.LogWarning("Color data associated with " + info.vpaintObject.name + " does not match the vertex cache. Transfer could not be performed.");
                continue;
            }

            pd.colors       = new Color[verts.Length];
            pd.transparency = new float[verts.Length];

            for (int v = 0; v < verts.Length; v++)
            {
                var   vert         = verts[v];
                float closestDist  = Mathf.Infinity;
                Color closestColor = Color.black;
                float closestTrans = 0f;

                for (int a = 0; a < oldVerts.Length; a++)
                {
                    var oldVert = transformMatrix.MultiplyPoint(oldVerts[a]);
                    var dist    = Vector3.Distance(oldVert, vert);
                    if (dist < closestDist)
                    {
                        closestDist  = dist;
                        closestColor = oldColors[a];
                        closestTrans = oldTrans[a];
                    }
                }

                pd.colors[v]       = closestColor;
                pd.transparency[v] = closestTrans;
            }
        }
    }
 void SingleInfoPanel(VPaintObjectInfo info)
 {
     VPaintGUIUtility.DrawColumnRow(24, () => {
         GUILayout.Label("Mesh Reference:");
         GUILayout.FlexibleSpace();
         if (!info.vpaintObject.originalMesh)
         {
             GUILayout.Label("MISSING");
         }
         else
         {
             bool isPersistent = EditorUtility.IsPersistent(info.vpaintObject.originalMesh);
             if (isPersistent)
             {
                 GUILayout.Label("Instanced");
                 if (GUILayout.Button("Break Instance"))
                 {
                     VPaint.Instance.BreakInstance(info.vpaintObject);
                 }
             }
             else
             {
                 GUILayout.Label("Unique");
                 GUI.enabled = false;
                 GUILayout.Button("Break Instance");
                 GUI.enabled = true;
             }
         }
     });
     VPaintGUIUtility.DrawColumnRow(24, () => {
         GUILayout.Label("Mesh Vertices:");
         GUILayout.FlexibleSpace();
         if (info.errors.Contains(VPaintObjectError.MissingMesh))
         {
             GUILayout.Label("MISSING");
         }
         else
         {
             GUILayout.Label(info.vpaintObject.GetMeshInstance().vertices.Length.ToString());
         }
     });
     VPaintGUIUtility.DrawColumnRow(24, () => {
         GUILayout.Label("Cached Vertices:");
         GUILayout.FlexibleSpace();
         if (info.vertexCache == null)
         {
             GUILayout.Label("None");
         }
         else
         {
             GUILayout.Label(info.vertexCache.vertices.Length.ToString());
         }
     });
 }
    void RadialSampleTransfer(VPaintObjectInfo info, float radius, float falloff)
    {
        var mesh = info.vpaintObject.originalMesh;

        if (!mesh)
        {
            mesh = info.vpaintObject.GetComponent <MeshFilter>().sharedMesh;
        }
        var verts    = mesh.vertices;
        var oldVerts = info.vertexCache.vertices;

        Matrix4x4 transformMatrix = Matrix4x4.TRS(vertexTransferOffset, Quaternion.Euler(vertexTransferRotate), vertexTransferScale);

        for (int i = 0; i < VPaint.Instance.layerStack.layers.Count; i++)
        {
            var layer = VPaint.Instance.layerStack.layers[i];

            var pd = layer.Get(info.vpaintObject);
            if (pd == null)
            {
                continue;
            }
            if (pd.colors.Length == verts.Length)
            {
                continue;
            }
            var oldColors = pd.colors;
            var oldTrans  = pd.transparency;

            if (oldVerts.Length != oldColors.Length)
            {
                Debug.LogWarning("Color data associated with " + info.vpaintObject.name + " does not match the vertex cache. Transfer could not be performed.");
                continue;
            }

            pd.colors       = new Color[verts.Length];
            pd.transparency = new float[verts.Length];

            for (int v = 0; v < verts.Length; v++)
            {
                var vert = verts[v];

                Vector4 col = Vector4.zero;
                float   tr  = 0;
                float   fac = 0;

                for (int o = 0; o < oldVerts.Length; o++)
                {
                    var oldVert  = transformMatrix.MultiplyPoint(oldVerts[o]);
                    var oldColor = oldColors[o];
                    var oldTr    = oldTrans[o];

                    float f = Mathf.Pow(1 - Mathf.Clamp01(Vector3.Distance(oldVert, vert) / radius), falloff);

                    col += (Vector4)oldColor * f;
                    tr  += oldTr * f;
                    fac += f;
                }

                if (fac != 0)
                {
                    col /= fac;
                    tr  /= fac;
                }

                pd.colors[v]       = (Color)col;
                pd.transparency[v] = tr;
            }
        }
    }
    public void RightPanel(float width)
    {
        rightPanelScroll = EditorGUILayout.BeginScrollView(rightPanelScroll);

        GUILayout.Space(5);

        if (selection.Count == 0)
        {
            GUILayout.Label(" ");
        }
        else
        {
            EditorGUILayout.BeginHorizontal();

            string title = "";

            VPaintObjectInfo[] selectionInfo = new VPaintObjectInfo[selection.Count];
            Dictionary <VPaintObjectError, List <VPaintObjectInfo> > errors = new Dictionary <VPaintObjectError, List <VPaintObjectInfo> >();

            for (int i = 0; i < selection.Count; i++)
            {
                var index = selection[i];
                var info  = VPaint.Instance.objectInfo[index];
                selectionInfo[i] = info;

                foreach (var err in info.errors)
                {
                    if (!errors.ContainsKey(err))
                    {
                        errors.Add(err, new List <VPaintObjectInfo>());
                    }
                    errors[err].Add(info);
                }

                if (i == 0)
                {
                    title = info.Name;
                }
                else
                {
                    title += ", " + info.Name;
                }
            }

            GUIStyle style = new GUIStyle(GUI.skin.label);
            style.fontSize = 20;

            var titleSize = style.CalcSize(new GUIContent(title));
            if (width - 42 < titleSize.x)
            {
                title = title.Substring(0, (int)(title.Length * ((width - 42) / titleSize.x))) + "...";
            }

            GUILayout.Label(title, style);

            EditorGUILayout.EndHorizontal();

            VPaintGUIUtility.BeginColumnView(width - 24);

            GUILayout.Space(10);

            if (selection.Count != 0)
            {
                MultiInfoPanel(selectionInfo);
            }

            GUILayout.Space(10);

            if (selection.Count == 1)
            {
                SingleInfoPanel(selectionInfo[0]);
            }

            GUILayout.Space(10);

            if (errors.Count != 0)
            {
                GUILayout.Label("The selected objects contain the following errors:");
                GUILayout.Space(10);
                foreach (var kvp in errors)
                {
                    var panel = GetErrorPanel(kvp.Key);
                    if (panel != null)
                    {
                        panel(kvp.Value.ToArray());
                    }
                    GUILayout.Space(10);
                }
            }
        }

        EditorGUILayout.EndScrollView();
    }