public void SavePalette(QT_ModifyColor MC)
    {
        string savedFile = EditorUtility.SaveFilePanelInProject("Save Palette", "Palette", "txt", "Save Palette File to Disk");

        if (savedFile.Length > 0 && savedFile.Contains("Assets"))
        {
            StreamWriter writer = File.CreateText(savedFile);

            writer.WriteLine("v1"); //6 lines of color

            for (int x = 0; x < MC.AllChannels.Length; x++)
            {
                writer.WriteLine(MC.AllChannels[x].Color[0] + "," + MC.AllChannels[x].Color[1] + "," + MC.AllChannels[x].Color[2] + "," + MC.AllChannels[x].Color[3] + "," + MC.AllChannels[x].hueRange + "," + MC.AllChannels[x].valRange);
            }
            writer.WriteLine("*"); //split between color data and shading data.
            writer.WriteLine(MC.preserveShading + "," + MC.Contrast + "," + MC.ContrastClamp1 + "," + MC.ContrastClamp2 + "," + MC.pwMeshOverride);

            AssetDatabase.Refresh();
            writer.Close();
        }
        else
        {
            EditorUtility.DisplayDialog("Invalid Folder", "Invalid Folder.\n\nPlease specify a folder within your Project.", "OK");
        }
    }
    void SetupInitialColors(QT_ModifyColor MC) //pulls original values from the original mesh
    {
        if (MC.originalValues == null)
        {
            //ifwe dont have orignals, populate THEM
            float h, s, v;
            MC.originalValues  = new float[MC.mesh.colors32.Length];
            MC.originalVCs     = new Color[MC.mesh.colors.Length];
            MC.originalVC_HSVs = new Vector3[MC.mesh.colors.Length];

            for (int c = 0; c < MC.originalValues.Length; c++)
            {
                MC.originalVCs[c] = MC.mesh.colors[c]; //copy vertex colors of original mesh


                Color vc = MC.mesh.colors[c];
                //Plug each vertex alpha that is found into their respective channel.
                float VA = MC.originalVCs[c].a * 255;
                //only pw meshes are masked by alpha values.
                //if (!MC.pwMeshOverride)
                //{
                if (VA == 3)    //3=1, 5=2, 8=3, 10=4. 13=5, 15=6 There will be at least a VA of 1.0 in max applied to a PW mesh.
                {
                    MC.AllChannels[0].targetVertices.Add(c);
                    MC.isPWMesh = true;
                }
                if (VA == 5)
                {
                    MC.AllChannels[1].targetVertices.Add(c);
                    MC.isPWMesh = true;
                }
                if (VA == 8)
                {
                    MC.AllChannels[2].targetVertices.Add(c);
                    MC.isPWMesh = true;
                }
                if (VA == 10)
                {
                    MC.AllChannels[3].targetVertices.Add(c);
                    MC.isPWMesh = true;
                }
                if (VA == 13)
                {
                    MC.AllChannels[4].targetVertices.Add(c);
                    MC.isPWMesh = true;
                }
                if (VA == 15)
                {
                    MC.AllChannels[5].targetVertices.Add(c);
                    MC.isPWMesh = true;
                }
                //  }
                Color.RGBToHSV(vc, out h, out s, out v);
                MC.originalValues[c]  = v;
                MC.originalVC_HSVs[c] = new Vector3(h, s, v);
            }
        }
    }
    //updates the list of vertices targeted by the hue and value range.
    public void UpdateTargetVertices(QT_ModifyColor MC, Color targetColor, int channelIndex)
    {
        if (MC.AllChannels[channelIndex].sampledColor == new Color(1, 0, 1, 0.123f)) //our do-nothing color.
        {
            return;
        }
        else
        {
            MC.AllChannels[channelIndex].targetVertices.Clear();

            float tcHue, tcSat, tcVal;
            Color.RGBToHSV(targetColor, out tcHue, out tcSat, out tcVal);

            float baseHue = (MC.AllChannels[channelIndex].hueRange); // / 2;
            float baseVal = (MC.AllChannels[channelIndex].valRange); // / 2;
            float baseSat = MC.AllChannels[channelIndex].satRange;

            float hueMin = Mathf.Clamp01(tcHue - baseHue);
            float hueMax = Mathf.Clamp01(tcHue + baseHue);
            float valMin = Mathf.Clamp01(tcVal - baseVal);
            float valMax = Mathf.Clamp01(tcVal + baseVal);
            float satMin = Mathf.Clamp01(tcSat - baseSat);
            float satMax = Mathf.Clamp01(tcSat + baseSat);

            for (int c = 0; c < MC.originalVCs.Length; c++)
            {
                //x =hue, y=sat, z=val
                if (MC.originalVC_HSVs[c].y >= satMin && MC.originalVC_HSVs[c].y <= satMax && MC.originalVC_HSVs[c].z >= valMin && MC.originalVC_HSVs[c].z <= valMax && MC.originalVC_HSVs[c].x >= hueMin && MC.originalVC_HSVs[c].x <= hueMax)
                {
                    MC.AllChannels[channelIndex].targetVertices.Add(c);
                }
            }

            /*
             * for (int x = 0; x < MC.AllChannels.Length; x++)
             * {
             *  for (int v = x + 1; v < MC.AllChannels.Length; v++)
             *  {
             *      int counter = 0;
             *      while (counter < MC.AllChannels[x].targetVertices.Count) //5 is length of X. 10 is length of v
             *      {
             *          if (MC.AllChannels[v].targetVertices.Contains(MC.AllChannels[x].targetVertices[counter]))
             *          {
             *              int targetIndex = MC.AllChannels[v].targetVertices.IndexOf(MC.AllChannels[x].targetVertices[counter]);
             *              MC.AllChannels[v].targetVertices.RemoveAt(targetIndex);
             *          }
             *          counter++;
             *      }
             *
             *  }
             * }
             * */
        }
    }
    private void LoadPalette(QT_ModifyColor MC)
    {
        string loadedFile = EditorUtility.OpenFilePanel("Load Palette", Application.dataPath, "txt");

        if (loadedFile.Length > 0)
        {
            //FileStream stream = new FileStream(loadedFile, FileMode.Open);
            StreamReader reader = File.OpenText(loadedFile);//new StreamReader(loadedFile);
            string       readme;

            int lineCounter = 0;
            while ((readme = reader.ReadLine()) != null)
            {
                string[] line = readme.Split(',');

                if (lineCounter >= 1 && lineCounter <= 6)
                {
                    MC.AllChannels[lineCounter - 1].Color[0] = float.Parse(line[0]);
                    MC.AllChannels[lineCounter - 1].Color[1] = float.Parse(line[1]);
                    MC.AllChannels[lineCounter - 1].Color[2] = float.Parse(line[2]);
                    MC.AllChannels[lineCounter - 1].Color[3] = float.Parse(line[3]);
                    MC.AllChannels[lineCounter - 1].hueRange = float.Parse(line[4]);
                    MC.AllChannels[lineCounter - 1].valRange = float.Parse(line[5]);
                }

                if (lineCounter == 8)
                {
                    MC.preserveShading = bool.Parse(line[0]);
                    MC.Contrast        = float.Parse(line[1]);
                    MC.ContrastClamp1  = float.Parse(line[2]);
                    MC.ContrastClamp2  = float.Parse(line[3]);
                    MC.pwMeshOverride  = bool.Parse(line[4]);
                    break;
                }

                lineCounter++;
            }

            reader.Close();

            for (int x = 0; x < MC.tempColors.Length; x++)
            {
                MC.tempColors[x].r = MC.AllChannels[x].Color[0];
                MC.tempColors[x].g = MC.AllChannels[x].Color[1];
                MC.tempColors[x].b = MC.AllChannels[x].Color[2];
                MC.tempColors[x].a = MC.AllChannels[x].Color[3];
            }
        }
    }
    public override void OnInspectorGUI()
    {
        if (Selection.activeGameObject)
        {
            MC = (QT_ModifyColor)target;
            QT_ModifyColorSample.GMC = MC;

            //do a bunch of checks to make sure it's a mesh/skinned mesh, prefab,and has a collider.
            if (RunInitialSetup(MC))
            {
                if (isSetup == false)
                {
                    //prep the data, put the working temp mesh in the mesh slots so people can see it in the sceneview.
                    if (MC.isMesh)
                    {
                        MC.mesh          = MC.sourceMF.sharedMesh;
                        MC.tempMesh      = DuplicateMesh(MC.mesh);
                        MC.tempMesh.name = "TEMP ModifyColor Mesh!";
                        SetupInitialColors(MC);
                        MC.sourceMF.sharedMesh = MC.tempMesh;
                        EditorUtility.SetDirty(MC.sourceMF);
                    }
                    else if (MC.isSM)
                    {
                        MC.mesh          = MC.sourceSMR.sharedMesh;
                        MC.tempMesh      = DuplicateMesh(MC.mesh);
                        MC.tempMesh.name = "TEMP ModifyColor Mesh!";
                        SetupInitialColors(MC);
                        MC.sourceSMR.sharedMesh = MC.tempMesh;
                        EditorUtility.SetDirty(MC.sourceSMR);
                    }
                    isSetup = true;
                }


                // if (MC.isPWMesh)
                //     MC.pwMeshOverride = EditorGUILayout.Toggle("New Channel Mapping", MC.pwMeshOverride);

                hideWireframe = EditorGUILayout.Toggle("Hide Wireframe", hideWireframe);
                EditorUtility.SetSelectedWireframeHidden(MC.gameObject.GetComponent <Renderer>(), hideWireframe);
                EditorGUILayout.Space();
                //found a PW mesh
                if (MC.isPWMesh && MC.pwMeshOverride == false)
                {
                    EditorGUILayout.HelpBox("PolyWorld Mesh Detected. Using preexisting channel mapping.", MessageType.Info);
                }

                MC.globalAlpha = EditorGUILayout.Slider("Global Alpha: ", MC.globalAlpha, 0f, 1f);



                //setup the UI for each color channel.
                for (int x = 0; x < MC.AllChannels.Length; x++)
                {
                    if (QT_ModifyColorSample.isSampling && QT_ModifyColorSample.channelIndex == x)
                    {
                        GUI.color += new Color(0f, -1f, -1f);
                        status     = "Click on a Triangle in Scene View";
                    }
                    else if (MC.AllChannels[x].targetVertices.Count == 0 || MC.AllChannels[x].targetVertices == null)// && MC.isPWMesh == false || MC.AllChannels[x].targetVertices.Count == 0 && MC.pwMeshOverride == true)
                    {
                        GUI.color += new Color(-.5f, 0.5f, -.5f);
                        status     = "Channel Clear";
                    }
                    else
                    {
                        GUI.color += new Color(+.5f, 1f, -.5f);
                        status     = "Channel in Use";
                    }

                    EditorGUILayout.BeginHorizontal();

                    GUILayout.Label("Channel " + (x + 1) + ": " + status);
                    GUI.color = new Color(1f, 1f, 1f);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    MC.tempColors[x] = EditorGUILayout.ColorField("Assign Color: ", MC.tempColors[x]);
                    //if it's not a polyworld mesh, or the override is enabled, let the user sample a color right on the mesh to override.
                    if (!MC.isPWMesh || MC.pwMeshOverride)
                    {
                        if (GUILayout.Button("Sample Color on Mesh"))
                        {
                            if (MC.GetComponent <Collider>().enabled)
                            {
                                //ghetto, I know. Love to know how else to do this.
                                QT_ModifyColorSample.isSampling   = !QT_ModifyColorSample.isSampling;
                                QT_ModifyColorSample.channelIndex = x;
                            }
                            else
                            {
                                EditorUtility.DisplayDialog("Enable Collider", "Please enable the collider to sample color data from the mesh.", "OK");
                            }
                        }
                    }
                    EditorGUILayout.EndHorizontal();

                    MC.tempSmoothness[x] = EditorGUILayout.Slider("Smoothness", MC.tempSmoothness[x], 0, 1);
                    MC.tempMetallic[x]   = EditorGUILayout.Slider("Metallic", MC.tempMetallic[x], 0, 1);

                    MC.AllChannels[x].Color = new float[4] {
                        MC.tempColors[x].r, MC.tempColors[x].g, MC.tempColors[x].b, MC.tempColors[x].a
                    };

                    MC.AllChannels[x].Smoothness = MC.tempSmoothness[x];
                    MC.AllChannels[x].Metallic   = MC.tempMetallic[x];


                    //Non Polyworld meshes, or PW meshes with the override, get to sample then tweak the hue/brightness range of the overridden color.
                    if (!MC.isPWMesh || MC.pwMeshOverride)
                    {
                        MC.AllChannels[x].hueRange = EditorGUILayout.Slider("Hue Range", MC.AllChannels[x].hueRange, 0, 1);
                        MC.AllChannels[x].satRange = EditorGUILayout.Slider("Saturation Range", MC.AllChannels[x].satRange, 0, 1);
                        MC.AllChannels[x].valRange = EditorGUILayout.Slider("Brightness Range", MC.AllChannels[x].valRange, 0, 1);

                        UpdateTargetVertices(MC, MC.AllChannels[x].sampledColor, x);
                        EditorGUILayout.Space();
                    }
                    EditorGUILayout.Space();
                }



                //keep the previous value range. Good for surface variety.
                MC.preserveShading = EditorGUILayout.Toggle("Preserve Shading", MC.preserveShading);
                if (MC.preserveShading)
                {
                    MC.Contrast       = EditorGUILayout.Slider("Fade:", MC.Contrast, 0f, 1f);
                    MC.ContrastClamp1 = EditorGUILayout.Slider("Shadows:", MC.ContrastClamp1, 0f, 1f);
                    MC.ContrastClamp2 = EditorGUILayout.Slider("Highlights:", MC.ContrastClamp2, 0f, 1f);
                }
                EditorGUILayout.Space();

                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Load Palette"))
                {
                    LoadPalette(MC);
                }

                if (GUILayout.Button("Save Palette"))
                {
                    SavePalette(MC);
                }

                //apply debug colors to easily see how they are applied.
                if (GUILayout.Button("Use Debug Colors"))
                {
                    MC.tempColors[0] = Color.red;
                    MC.tempColors[1] = Color.green;
                    MC.tempColors[2] = Color.blue;
                    MC.tempColors[3] = Color.yellow;
                    MC.tempColors[4] = Color.magenta;
                    MC.tempColors[5] = Color.white;
                }
                EditorGUILayout.EndHorizontal();
                //clear all data.
                if (GUILayout.Button("Reset Mesh"))
                {
                    QT_ModifyColorSample.isSampling = false;

                    for (int p = 0; p < MC.AllChannels.Length; p++)
                    {
                        //if (!MC.isPWMesh || MC.pwMeshOverride)
                        MC.AllChannels[p].targetVertices.Clear();
                        MC.AllChannels[p].sampledColor = new Color(1, 0, 1, 0.123f);
                        MC.AllChannels[p].hueRange     = .5f;
                        MC.AllChannels[p].valRange     = .25f;
                        MC.isPWMesh = false;
                    }

                    isSetup = false;
                }

                EditorGUILayout.Space();
                //update the mesh collider on the new game object.
                MC.updateMeshCollider = EditorGUILayout.Toggle("Update Mesh Collider", MC.updateMeshCollider);
                //replace the current prefab with the new gameobject with the new colored mesh.
                MC.Replace = EditorGUILayout.Toggle("Overwrite Prefab", MC.Replace);
                //if we don't replace the prefab, create a new one.
                if (!MC.Replace)
                {
                    MC.newPrefabName = EditorGUILayout.TextField("New Prefab Name:", MC.newPrefabName);
                    if (MC.newPrefabName.Equals(MC.gameObject.transform.root.gameObject.name))
                    {
                        EditorGUILayout.HelpBox("New Prefab Name is the same as the current root prefab name. Please providea unique name for the new gameobject.", MessageType.Warning);
                    }
                }
                //else
                MC.meshFileName = EditorGUILayout.TextField("Mesh Filename:", MC.meshFileName);


                //if the original value range is empty, setup them up and normalize.
                if (MC.originalValues != null)
                {
                    MC.newValues  = new float[MC.tempMesh.colors32.Length];
                    MC.newShading = new float[MC.tempMesh.colors32.Length];

                    for (int x = 0; x < MC.newValues.Length; x++)
                    {
                        MC.newValues[x]  = MC.originalValues[x];
                        MC.newShading[x] = MC.originalValues[x];
                    }

                    MC.newValues = MC.RemapFloats(MC.originalValues, MC.Highlights, MC.Shadows);

                    MC.newShading = MC.RemapFloats(MC.originalValues, 0f, 1f);

                    for (int p = 0; p < MC.newShading.Length; p++)
                    {
                        MC.newShading[p]  = Mathf.Clamp(MC.newShading[p], MC.ContrastClamp1, MC.ContrastClamp2);
                        MC.newShading[p] += MC.Contrast;
                        MC.newShading[p]  = Mathf.Clamp01(MC.newShading[p]);
                    }

                    //copy the originalvcs into the newcolors array to get overwritten by even newer colors.
                    Color[]   newColors = new Color[MC.originalVCs.Length];
                    Vector2[] newUV4s   = new Vector2[MC.originalVCs.Length];

                    for (int b = 0; b < newColors.Length; b++)
                    {
                        newColors[b] = MC.originalVCs[b];
                    }

                    //in every channel, go through every target vertex and apply the color
                    //we go in reverse order so the colors are layered accordingly.

                    for (int c = MC.AllChannels.Length - 1; c >= 0; c--)
                    {
                        for (int z = 0; z < MC.AllChannels[c].targetVertices.Count; z++)
                        {
                            int vertIndex = MC.AllChannels[c].targetVertices[z];
                            //lerp between the allchannel color and newcolors via alpha of the allchannels
                            //allchannels corresponds to the channels in the inspector and its data
                            float newR = Mathf.Lerp(newColors[vertIndex].r, MC.AllChannels[c].Color[0], MC.AllChannels[c].Color[3] * MC.globalAlpha);
                            float newG = Mathf.Lerp(newColors[vertIndex].g, MC.AllChannels[c].Color[1], MC.AllChannels[c].Color[3] * MC.globalAlpha);
                            float newB = Mathf.Lerp(newColors[vertIndex].b, MC.AllChannels[c].Color[2], MC.AllChannels[c].Color[3] * MC.globalAlpha);

                            float channelAlpha = SetChannelVertexAlpha(c); //add the correct alpha color value per channel so it becomes a PW mesh

                            newColors[vertIndex] = new Color(newR, newG, newB);
                            //now to a global fade
                            if (MC.preserveShading)
                            {
                                newColors[vertIndex] *= MC.newShading[vertIndex];
                            }

                            newColors[vertIndex].a = channelAlpha;
                            newUV4s[vertIndex].x   = MC.AllChannels[c].Smoothness;
                            newUV4s[vertIndex].y   = MC.AllChannels[c].Metallic;
                        }
                    }
                    //assign the new color choices.
                    MC.AssignVCs(newColors);
                    MC.AssignUV4s(newUV4s);
                }

                if (GUILayout.Button("Save Changes to Disk"))
                {
                    //if we input bad stuff
                    if (MC.Replace == false && MC.newPrefabName.Equals(MC.gameObject.transform.root.gameObject.name))
                    {
                        EditorUtility.DisplayDialog("Bad Prefab Name", "You have chosen a new prefab name that is the same as the old one. Please give a unique name to the new prefab.", "OK");
                    }
                    else
                    {
                        //begin to write all the new data.
                        WriteData();
                        //delete the modifycolor component on the active game object since we don't need it anymore.
                        DestroyImmediate(activeGO.GetComponent <QT_ModifyColor>());
                    }
                }
            }
            if (GUILayout.Button("Help"))
            {
                Application.OpenURL("http://qt-ent.com/PolyWorld/scripts/");
            }
        }
    }
    //pulls original values from the original mesh
    void SetupInitialColors(QT_ModifyColor MC)
    {
        if (MC.originalValues == null)
        {
            //ifwe dont have orignals, populate THEM
            float h, s, v;
            MC.originalValues = new float[MC.mesh.colors32.Length];
            MC.originalVCs = new Color[MC.mesh.colors.Length];
            MC.originalVC_HSVs = new Vector3[MC.mesh.colors.Length];

            for (int c = 0; c < MC.originalValues.Length; c++)
            {
                MC.originalVCs[c] = MC.mesh.colors[c];
                Color vc = MC.mesh.colors[c];
                //Plug each vertex alpha that is found into their respective channel.
                float VA = MC.originalVCs[c].a * 255;
                //only pw meshes are masked by alpha values.
                if (!MC.pwMeshOverride)
                {
                    if (VA == 3)//3=1, 5=2, 8=3, 10=4. 13=5, 15=6 There will be at least a VA of 1.0 in max applied to a PW mesh.
                    {
                        MC.AllChannels[0].targetVertices.Add(c);
                        MC.isPWMesh = true;
                    }
                    if (VA == 5)
                    {
                        MC.AllChannels[1].targetVertices.Add(c);
                        MC.isPWMesh = true;
                    }
                    if (VA == 8)
                    {
                        MC.AllChannels[2].targetVertices.Add(c);
                        MC.isPWMesh = true;
                    }
                    if (VA == 10)
                    {
                        MC.AllChannels[3].targetVertices.Add(c);
                        MC.isPWMesh = true;
                    }
                    if (VA == 13)
                    {
                        MC.AllChannels[4].targetVertices.Add(c);
                        MC.isPWMesh = true;
                    }
                    if (VA == 15)
                    {
                        MC.AllChannels[5].targetVertices.Add(c);
                        MC.isPWMesh = true;
                    }
                }
                EditorGUIUtility.RGBToHSV(vc, out h, out s, out v);
                MC.originalValues[c] = v;
                MC.originalVC_HSVs[c] = new Vector3(h, s, v);
            }

        }
    }
    //checks to see if it's a mesh and prefab and has a collider.
    private bool RunInitialSetup(QT_ModifyColor MC)
    {
        bool pass = true;

        activeGO     = Selection.activeGameObject;
        activeRootGO = Selection.activeGameObject.transform.root.gameObject;

        if (PrefabUtility.GetPrefabType(activeRootGO) != PrefabType.PrefabInstance)
        {
            EditorGUILayout.HelpBox(MC.gameObject.name + " is not a Prefab. Please convert this gameobject hierarchy to a prefab before using the Modify Color script.", MessageType.Warning);
            pass = false;
            return(pass);
        }
        else
        {
            pass = true;
        }

        MC.sourceMF = activeGO.GetComponent <MeshFilter>();
        if (MC.sourceMF)
        {
            MC.isMesh = true;
        }

        MC.sourceSMR = activeGO.GetComponent <SkinnedMeshRenderer>();
        if (MC.sourceSMR)
        {
            MC.isSM = true;
        }

        if (!MC.isMesh && !MC.isSM)
        {
            EditorGUILayout.HelpBox(MC.gameObject.name + " does not contain a mesh. Modify Color requires a gameobject with a Meshfilter or SkinnedMeshRenderer component and a mesh.", MessageType.Warning);
            pass = false;
            return(pass);
        }
        else
        {
            pass = true;
        }

        if (!MC.GetComponent <MeshCollider>())
        {
            EditorGUILayout.HelpBox("This GameObject temporarily requires a mesh collider to accurately specify color changes.", MessageType.Warning);
            pass = false;
            return(pass);
        }
        else
        {
            MC.hasCollider = true;
            pass           = true;
        }

        if (MC.GetComponent <MeshCollider>().sharedMesh == null)
        {
            EditorGUILayout.HelpBox("The MeshCollider contains no reference to a mesh. Provide one to continue.", MessageType.Warning);
            pass = false;
            return(pass);
        }
        else
        {
            pass = true;
        }

        /*
         * if (pass)
         * {
         *  GOHierarchy = new List<Transform>();
         *  //disable the other children because it messes with the modifycolor script.
         *  CollectGOs(activeRootGO);
         *  foreach (Transform child in GOHierarchy)
         *  {
         *      if (!child.gameObject.name.Equals(activeGO.name) || child.gameObject.activeInHierarchy == true)
         *      {
         *
         *          if (!child.GetComponent<MeshFilter>() || !child.GetComponent<SkinnedMeshRenderer>())
         *              GOHierarchy.Remove(child);
         *          else
         *              child.gameObject.SetActive(false);
         *      }
         *
         *  }
         *
         *
         *
         * }*/
        return(pass);
    }
    //checks to see if it's a mesh and prefab and has a collider.
    private bool RunInitialSetup(QT_ModifyColor MC)
    {
        bool pass=true;
        activeGO = Selection.activeGameObject;
        activeRootGO = Selection.activeGameObject.transform.root.gameObject;

        if (PrefabUtility.GetPrefabType(activeRootGO) != PrefabType.PrefabInstance)
        {
            EditorGUILayout.HelpBox(MC.gameObject.name + " is not a Prefab. Please convert this gameobject hierarchy to a prefab before using the Modify Color script.", MessageType.Warning);
            pass = false;
            return pass;
        }
        else
            pass = true;

        MC.sourceMF = activeGO.GetComponent<MeshFilter>();
        if (MC.sourceMF)
            MC.isMesh = true;

        MC.sourceSMR = activeGO.GetComponent<SkinnedMeshRenderer>();
        if (MC.sourceSMR)
            MC.isSM = true;

        if (!MC.isMesh && !MC.isSM)
        {
            EditorGUILayout.HelpBox(MC.gameObject.name + " does not contain a mesh. Modify Color requires a gameobject with a Meshfilter or SkinnedMeshRenderer component and a mesh.", MessageType.Warning);
            pass = false;
            return pass;
        }
        else
            pass = true;

        if (!MC.GetComponent<MeshCollider>())
        {
            EditorGUILayout.HelpBox("This GameObject temporarily requires a mesh collider to accurately specify color changes.", MessageType.Warning);
            pass = false;
            return pass;
        }
        else
        {
            MC.hasCollider = true;
            pass = true;
        }

        if (MC.GetComponent<MeshCollider>().sharedMesh == null)
        {
            EditorGUILayout.HelpBox("The MeshCollider contains no reference to a mesh. Provide one to continue.", MessageType.Warning);
            pass = false;
            return pass;
        }
        else
            pass = true;

        /*
        if (pass)
        {
            GOHierarchy = new List<Transform>();
            //disable the other children because it messes with the modifycolor script.
            CollectGOs(activeRootGO);
            foreach (Transform child in GOHierarchy)
            {
                if (!child.gameObject.name.Equals(activeGO.name) || child.gameObject.activeInHierarchy == true)
                {

                    if (!child.GetComponent<MeshFilter>() || !child.GetComponent<SkinnedMeshRenderer>())
                        GOHierarchy.Remove(child);
                    else
                        child.gameObject.SetActive(false);
                }

            }

        }*/
        return pass;
    }
    private void LoadPalette(QT_ModifyColor MC)
    {
        string loadedFile = EditorUtility.OpenFilePanel("Load Palette", Application.dataPath, "txt");
        if (loadedFile.Length > 0)
        {
            //FileStream stream = new FileStream(loadedFile, FileMode.Open);
            StreamReader reader = File.OpenText(loadedFile);//new StreamReader(loadedFile);
            string readme;

            int lineCounter = 0;
            while ((readme = reader.ReadLine()) != null)
            {

                string[] line = readme.Split(',');

                if (lineCounter >= 1 && lineCounter <= 6)
                {

                    MC.AllChannels[lineCounter-1].Color[0] = float.Parse(line[0]);
                    MC.AllChannels[lineCounter-1].Color[1] = float.Parse(line[1]);
                    MC.AllChannels[lineCounter-1].Color[2] = float.Parse(line[2]);
                    MC.AllChannels[lineCounter-1].Color[3] = float.Parse(line[3]);
                    MC.AllChannels[lineCounter-1].hueRange = float.Parse(line[4]);
                    MC.AllChannels[lineCounter-1].valRange = float.Parse(line[5]);
                }

                if (lineCounter ==8)
                {
                    MC.preserveShading = bool.Parse(line[0]);
                    MC.Contrast = float.Parse(line[1]);
                    MC.ContrastClamp1 = float.Parse(line[2]);
                    MC.ContrastClamp2 = float.Parse(line[3]);
                    MC.pwMeshOverride = bool.Parse(line[4]);
                    break;
                }

                lineCounter++;
            }

            reader.Close();

            for (int x = 0; x < MC.tempColors.Length; x++)
            {
                MC.tempColors[x].r = MC.AllChannels[x].Color[0];
                MC.tempColors[x].g = MC.AllChannels[x].Color[1];
                MC.tempColors[x].b = MC.AllChannels[x].Color[2];
                MC.tempColors[x].a = MC.AllChannels[x].Color[3];
            }
        }
    }
    public override void OnInspectorGUI()
    {
        if (Selection.activeGameObject)
        {
            MC = (QT_ModifyColor)target;
            QT_ModifyColorSample.GMC = MC;

            //do a bunch of checks to make sure it's a mesh/skinned mesh, prefab,and has a collider.
            if (RunInitialSetup(MC))
            {
                if (isSetup == false)
                {

                        //prep the data, put the working temp mesh in the mesh slots so people can see it in the sceneview.
                        if (MC.isMesh)
                        {
                            MC.mesh = MC.sourceMF.sharedMesh;
                            MC.tempMesh = DuplicateMesh(MC.mesh);
                            MC.tempMesh.name = "TEMP ModifyColor Mesh!";
                            SetupInitialColors(MC);
                            MC.sourceMF.sharedMesh = MC.tempMesh;
                            EditorUtility.SetDirty(MC.sourceMF);
                        }
                        else if (MC.isSM)
                        {
                            MC.mesh = MC.sourceSMR.sharedMesh;
                            MC.tempMesh = DuplicateMesh(MC.mesh);
                            MC.tempMesh.name = "TEMP ModifyColor Mesh!";
                            SetupInitialColors(MC);
                            MC.sourceSMR.sharedMesh = MC.tempMesh;
                            EditorUtility.SetDirty(MC.sourceSMR);
                        }
                        isSetup = true;
                }

               // if (MC.isPWMesh)
               //     MC.pwMeshOverride = EditorGUILayout.Toggle("New Channel Mapping", MC.pwMeshOverride);

                hideWireframe = EditorGUILayout.Toggle("Hide Wireframe", hideWireframe);
                EditorUtility.SetSelectedWireframeHidden(MC.gameObject.GetComponent<Renderer>(), hideWireframe);
                EditorGUILayout.Space();
                //found a PW mesh
                if (MC.isPWMesh && MC.pwMeshOverride == false)
                    EditorGUILayout.HelpBox("PolyWorld Mesh Detected. Using preexisting channel mapping.", MessageType.Info);

                MC.globalAlpha = EditorGUILayout.Slider("Global Alpha: ", MC.globalAlpha, 0f, 1f);

                //setup the UI for each color channel.
                for (int x = 0; x < MC.AllChannels.Length; x++)
                {

                    if (QT_ModifyColorSample.isSampling && QT_ModifyColorSample.channelIndex == x)
                    {
                        GUI.color += new Color(0f, -1f, -1f);
                        status = "Click on a Triangle in Scene View";
                    }
                    else if (MC.AllChannels[x].targetVertices.Count == 0 || MC.AllChannels[x].targetVertices == null)// && MC.isPWMesh == false || MC.AllChannels[x].targetVertices.Count == 0 && MC.pwMeshOverride == true)
                    {
                        GUI.color += new Color(-.5f, 0.5f, -.5f);
                        status = "Channel Clear";
                    }
                    else
                    {
                        GUI.color += new Color(+.5f, 1f, -.5f);
                        status = "Channel in Use";
                    }

                    EditorGUILayout.BeginHorizontal();

                    GUILayout.Label("Channel " + (x + 1) + ": " + status);
                    GUI.color = new Color(1f, 1f, 1f);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    MC.tempColors[x] = EditorGUILayout.ColorField("Assign Color: ", MC.tempColors[x]);
                    //if it's not a polyworld mesh, or the override is enabled, let the user sample a color right on the mesh to override.
                    if (!MC.isPWMesh || MC.pwMeshOverride)
                    {
                        if (GUILayout.Button("Sample Color on Mesh"))
                        {
                            if (MC.GetComponent<Collider>().enabled)
                            {
                                //ghetto, I know. Love to know how else to do this.
                                QT_ModifyColorSample.isSampling = !QT_ModifyColorSample.isSampling;
                                QT_ModifyColorSample.channelIndex = x;
                            }
                            else
                                EditorUtility.DisplayDialog("Enable Collider", "Please enable the collider to sample color data from the mesh.", "OK");

                        }
                    }
                    EditorGUILayout.EndHorizontal();
                    MC.AllChannels[x].Color = new float[4] { MC.tempColors[x].r, MC.tempColors[x].g, MC.tempColors[x].b, MC.tempColors[x].a };
                    //Non Polyworld meshes, or PW meshes with the override, get to sample then tweak the hue/brightness range of the overridden color.
                    if (!MC.isPWMesh || MC.pwMeshOverride)
                    {
                        MC.AllChannels[x].hueRange = EditorGUILayout.Slider("Hue Range", MC.AllChannels[x].hueRange, 0, 1);
                        MC.AllChannels[x].satRange = EditorGUILayout.Slider("Saturation Range", MC.AllChannels[x].satRange, 0, 1);
                        MC.AllChannels[x].valRange = EditorGUILayout.Slider("Brightness Range", MC.AllChannels[x].valRange, 0, 1);
                        UpdateTargetVertices(MC, MC.AllChannels[x].sampledColor, x);
                        EditorGUILayout.Space();
                    }
                    EditorGUILayout.Space();
                }

                //keep the previous value range. Good for surface variety.
                MC.preserveShading = EditorGUILayout.Toggle("Preserve Shading", MC.preserveShading);
                if (MC.preserveShading)
                {
                    MC.Contrast = EditorGUILayout.Slider("Fade:", MC.Contrast, 0f, 1f);
                    MC.ContrastClamp1 = EditorGUILayout.Slider("Shadows:", MC.ContrastClamp1, 0f, 1f);
                    MC.ContrastClamp2 = EditorGUILayout.Slider("Highlights:", MC.ContrastClamp2, 0f, 1f);
                }
                EditorGUILayout.Space();

                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Load Palette"))
                    LoadPalette(MC);

                if (GUILayout.Button("Save Palette"))
                    SavePalette(MC);

                //apply debug colors to easily see how they are applied.
                if (GUILayout.Button("Use Debug Colors"))
                {
                    MC.tempColors[0] = Color.red;
                    MC.tempColors[1] = Color.green;
                    MC.tempColors[2] = Color.blue;
                    MC.tempColors[3] = Color.yellow;
                    MC.tempColors[4] = Color.magenta;
                    MC.tempColors[5] = Color.white;
                }
                EditorGUILayout.EndHorizontal();
                //clear all data.
                if (GUILayout.Button("Reset Mesh"))
                {

                    QT_ModifyColorSample.isSampling = false;

                    for (int p = 0; p < MC.AllChannels.Length; p++)
                    {
                        //if (!MC.isPWMesh || MC.pwMeshOverride)
                            MC.AllChannels[p].targetVertices.Clear();
                        MC.AllChannels[p].sampledColor = new Color(1, 0, 1, 0.123f);
                        MC.AllChannels[p].hueRange = .5f;
                        MC.AllChannels[p].valRange = .25f;
                        MC.isPWMesh = false;
                    }

                    isSetup = false;

                }

                EditorGUILayout.Space();
                //update the mesh collider on the new game object.
                MC.updateMeshCollider = EditorGUILayout.Toggle("Update Mesh Collider", MC.updateMeshCollider);
                //replace the current prefab with the new gameobject with the new colored mesh.
                MC.Replace = EditorGUILayout.Toggle("Overwrite Prefab", MC.Replace);
                //if we don't replace the prefab, create a new one.
                if (!MC.Replace)
                {
                    MC.newPrefabName = EditorGUILayout.TextField("New Prefab Name:", MC.newPrefabName);
                    if (MC.newPrefabName.Equals(MC.gameObject.transform.root.gameObject.name))
                        EditorGUILayout.HelpBox("New Prefab Name is the same as the current root prefab name. Please providea unique name for the new gameobject.", MessageType.Warning);
                }
                //else
                MC.meshFileName = EditorGUILayout.TextField("Mesh Filename:", MC.meshFileName);

                //if the original value range is empty, setup them up and normalize.
                if (MC.originalValues != null)
                {
                    MC.newValues = new float[MC.tempMesh.colors32.Length];
                    MC.newShading = new float[MC.tempMesh.colors32.Length];

                    for (int x = 0; x < MC.newValues.Length; x++)
                    {
                        MC.newValues[x] = MC.originalValues[x];
                        MC.newShading[x] = MC.originalValues[x];
                    }

                    MC.newValues = MC.RemapFloats(MC.originalValues, MC.Highlights, MC.Shadows);

                    MC.newShading = MC.RemapFloats(MC.originalValues, 0f, 1f);

                    for (int p = 0; p < MC.newShading.Length; p++)
                    {
                        MC.newShading[p] = Mathf.Clamp(MC.newShading[p], MC.ContrastClamp1, MC.ContrastClamp2);
                        MC.newShading[p] += MC.Contrast;
                        MC.newShading[p] = Mathf.Clamp01(MC.newShading[p]);
                    }

                    //copy the originalvcs into the newcolors array to get overwritten by even newer colors.
                    Color[] newColors = new Color[MC.originalVCs.Length];
                    for (int b = 0; b < newColors.Length; b++)
                        newColors[b] = MC.originalVCs[b];

                    //in every channel, go through every target vertex and apply the color
                    //we go in reverse order so the colors are layered accordingly.

                    for (int c=MC.AllChannels.Length-1;c>=0;c--)//int c = 0; c < MC.AllChannels.Length; c++)
                    {
                        for (int z = 0; z < MC.AllChannels[c].targetVertices.Count; z++)
                        {
                            int vertIndex = MC.AllChannels[c].targetVertices[z];
                            //lerp between the allchannel color and newcolors via alpha of the allchannels
                            float newR = Mathf.Lerp(newColors[vertIndex].r, MC.AllChannels[c].Color[0], MC.AllChannels[c].Color[3] * MC.globalAlpha);
                            float newG = Mathf.Lerp(newColors[vertIndex].g, MC.AllChannels[c].Color[1], MC.AllChannels[c].Color[3] * MC.globalAlpha);
                            float newB = Mathf.Lerp(newColors[vertIndex].b, MC.AllChannels[c].Color[2], MC.AllChannels[c].Color[3] * MC.globalAlpha);
                            newColors[vertIndex] = new Color(newR, newG, newB);
                            //now to a global fade
                            if (MC.preserveShading)
                                newColors[vertIndex] *= MC.newShading[vertIndex];
                        }
                    }
                    //assign the new color choices.
                    MC.AssignVCs(newColors);
                }

                if (GUILayout.Button("Save Changes to Disk"))
                {
                    //if we input bad stuff
                    if (MC.Replace == false && MC.newPrefabName.Equals(MC.gameObject.transform.root.gameObject.name))
                        EditorUtility.DisplayDialog("Bad Prefab Name", "You have chosen a new prefab name that is the same as the old one. Please give a unique name to the new prefab.", "OK");
                    else
                    {
                        //begin to write all the new data.
                        WriteData();
                        //delete the modifycolor component on the active game object since we don't need it anymore.
                        DestroyImmediate(activeGO.GetComponent<QT_ModifyColor>());
                    }
                }
            }
            if (GUILayout.Button("Help"))
            {
                Application.OpenURL("http://qt-ent.com/PolyWorld/scripts/");
            }
        }
    }
    //updates the list of vertices targeted by the hue and value range.
    public void UpdateTargetVertices(QT_ModifyColor MC, Color targetColor, int channelIndex)
    {
        if (MC.AllChannels[channelIndex].sampledColor == new Color(1, 0, 1, 0.123f)) //our do-nothing color.
        {
            return;
        }
        else
        {
            MC.AllChannels[channelIndex].targetVertices.Clear();

            float tcHue, tcSat, tcVal;
            EditorGUIUtility.RGBToHSV(targetColor, out tcHue, out tcSat, out tcVal);

            float baseHue = (MC.AllChannels[channelIndex].hueRange);// / 2;
            float baseVal = (MC.AllChannels[channelIndex].valRange);// / 2;
            float baseSat = MC.AllChannels[channelIndex].satRange;

            float hueMin = Mathf.Clamp01(tcHue - baseHue);
            float hueMax = Mathf.Clamp01(tcHue + baseHue);
            float valMin = Mathf.Clamp01(tcVal - baseVal);
            float valMax = Mathf.Clamp01(tcVal + baseVal);
            float satMin = Mathf.Clamp01(tcSat - baseSat);
            float satMax = Mathf.Clamp01(tcSat + baseSat);

            for (int c = 0; c < MC.originalVCs.Length; c++)
            {
                //x =hue, y=sat, z=val
                if (MC.originalVC_HSVs[c].y >= satMin && MC.originalVC_HSVs[c].y <= satMax && MC.originalVC_HSVs[c].z >= valMin && MC.originalVC_HSVs[c].z <= valMax && MC.originalVC_HSVs[c].x >= hueMin && MC.originalVC_HSVs[c].x <= hueMax)
                    MC.AllChannels[channelIndex].targetVertices.Add(c);

            }

            /*
            for (int x = 0; x < MC.AllChannels.Length; x++)
            {
                for (int v = x + 1; v < MC.AllChannels.Length; v++)
                {
                    int counter = 0;
                    while (counter < MC.AllChannels[x].targetVertices.Count) //5 is length of X. 10 is length of v
                    {
                        if (MC.AllChannels[v].targetVertices.Contains(MC.AllChannels[x].targetVertices[counter]))
                        {
                            int targetIndex = MC.AllChannels[v].targetVertices.IndexOf(MC.AllChannels[x].targetVertices[counter]);
                            MC.AllChannels[v].targetVertices.RemoveAt(targetIndex);
                        }
                        counter++;
                    }

                }
            }
             * */

        }
    }
    public void SavePalette(QT_ModifyColor MC)
    {
        string savedFile = EditorUtility.SaveFilePanelInProject("Save Palette", "Palette", "txt", "Save Palette File to Disk");

        if (savedFile.Length > 0 && savedFile.Contains("Assets"))
        {
            StreamWriter writer = File.CreateText(savedFile);

            writer.WriteLine("v1"); //6 lines of color

            for (int x = 0; x < MC.AllChannels.Length; x++)
            {
                writer.WriteLine(MC.AllChannels[x].Color[0] + "," + MC.AllChannels[x].Color[1] + "," + MC.AllChannels[x].Color[2] + "," + MC.AllChannels[x].Color[3] + "," + MC.AllChannels[x].hueRange + "," + MC.AllChannels[x].valRange);

            }
            writer.WriteLine("*"); //split between color data and shading data.
            writer.WriteLine(MC.preserveShading+","+MC.Contrast+","+MC.ContrastClamp1+","+MC.ContrastClamp2+","+ MC.pwMeshOverride);

            AssetDatabase.Refresh();
            writer.Close();

        }
        else
            EditorUtility.DisplayDialog("Invalid Folder", "Invalid Folder.\n\nPlease specify a folder within your Project.", "OK");
    }