Exemple #1
0
    private static void ImportBays(XmlDocument xml, BuildrData data)
    {
        foreach (XmlNode node in xml.SelectNodes("buildr/bays/bay"))
        {
            BuildrBay bay = new BuildrBay("");
            data.bays.Add(bay);

            bay.name = node["bayName"].FirstChild.Value;
            bay.isOpening = bool.Parse(node["isOpening"].FirstChild.Value);
            bay.openingWidth = float.Parse(node["bayOpeningWidth"].FirstChild.Value);
            bay.openingHeight = float.Parse(node["bayOpeningHeight"].FirstChild.Value);
            bay.minimumBayWidth = float.Parse(node["bayMinimumBayWidth"].FirstChild.Value);
            bay.openingWidthRatio = float.Parse(node["bayOpeningWidthRatio"].FirstChild.Value);
            bay.openingHeightRatio = float.Parse(node["bayOpeningHeightRatio"].FirstChild.Value);
            bay.openingDepth = float.Parse(node["bayOpeningDepth"].FirstChild.Value);
            bay.columnDepth = float.Parse(node["bayColumnDepth"].FirstChild.Value);
            bay.rowDepth = float.Parse(node["bayRowDepth"].FirstChild.Value);
            bay.crossDepth = float.Parse(node["bayCrossDepth"].FirstChild.Value);

            for (int i = 0; i < 8; i++)
            {
                bay.textureValues[i] = int.Parse(node.SelectNodes("bayTextures/texture")[i].FirstChild.Value);
                bay.flipValues[i] = node.SelectNodes("bayflipvalues/flipvalue")[i].FirstChild.Value == valueTrue;
            }
        }
    }
Exemple #2
0
    public void RemoveTexture(BuildrTexture bTexture)
    {
        int bTextureIndex = textures.IndexOf(bTexture);

        textures.Remove(bTexture);

        foreach (BuildrFacadeDesign facade in facades)
        {
            int numberOfFacadeTextures = facade.textureValues.Length;
            for (int i = 0; i < numberOfFacadeTextures; i++)
            {
                if (facade.textureValues[i] >= bTextureIndex && facade.textureValues[i] > 0)
                {
                    facade.textureValues[i]--;
                }
            }

            BuildrBay bay = facade.simpleBay;
            int       numberOfBayTextures = bay.textureValues.Length;
            for (int i = 0; i < numberOfBayTextures; i++)
            {
                if (bay.textureValues[i] >= bTextureIndex && bay.textureValues[i] > 0)
                {
                    bay.textureValues[i]--;
                }
            }
        }
        foreach (BuildrRoofDesign roof in roofs)
        {
            int numberOfRoofTextures = roof.textureValues.Length;
            for (int i = 0; i < numberOfRoofTextures; i++)
            {
                if (roof.textureValues[i] >= bTextureIndex && roof.textureValues[i] > 0)
                {
                    roof.textureValues[i]--;
                }
            }
        }
        foreach (BuildrBay bay in bays)
        {
            int numberOfBayTextures = bay.textureValues.Length;
            for (int i = 0; i < numberOfBayTextures; i++)
            {
                if (bay.textureValues[i] >= bTextureIndex && bay.textureValues[i] > 0)
                {
                    bay.textureValues[i]--;
                }
            }
        }
    }
Exemple #3
0
    public int wallTexture = 0;//this is use then there are no windows

    public BuildrBay Duplicate()
    {
        BuildrBay newBay = new BuildrBay(name + " copy");

        newBay.isOpening          = isOpening;
        newBay.openingWidth       = openingWidth;
        newBay.openingHeight      = openingHeight;
        newBay.minimumBayWidth    = minimumBayWidth;
        newBay.openingWidthRatio  = openingWidthRatio;  //the ratio of space between the left and right walls from the opening
        newBay.openingHeightRatio = openingHeightRatio; //the ratio of space between above and below the opening
        newBay.openingDepth       = openingDepth;
        newBay.columnDepth        = columnDepth;
        newBay.rowDepth           = rowDepth;
        newBay.crossDepth         = crossDepth;
        newBay.textureValues      = (int[])textureValues.Clone();
        newBay.flipValues         = (bool[])flipValues.Clone();
        newBay.bayModel           = bayModel;

        return(newBay);
    }
    public BuildrBay Duplicate()
    {
        BuildrBay newBay = new BuildrBay(name + " copy");
        newBay.isOpening = isOpening;
        newBay.openingWidth = openingWidth;
        newBay.openingHeight = openingHeight;
        newBay.minimumBayWidth = minimumBayWidth;
        newBay.openingWidthRatio = openingWidthRatio;//the ratio of space between the left and right walls from the opening
        newBay.openingHeightRatio = openingHeightRatio;//the ratio of space between above and below the opening
        newBay.openingDepth = openingDepth;
        newBay.columnDepth = columnDepth;
        newBay.rowDepth = rowDepth;
        newBay.crossDepth = crossDepth;
        newBay.textureValues = (int[])textureValues.Clone();
        newBay.flipValues = (bool[])flipValues.Clone();
        newBay.bayModel = bayModel;

        return newBay;
    }
    public static void InspectorGUI(BuildrEditMode editMode, BuildrData _data)
    {
        int helpWidth = 20;

        data = _data;

        Undo.RecordObject(data, "Facade Modified");

        BuildrFacadeDesign[] facades = data.facades.ToArray();
        int numberOfFacades = facades.Length;
        selectedFacade = Mathf.Clamp(selectedFacade, 0, numberOfFacades - 1);

        if (numberOfFacades == 0)
        {
            EditorGUILayout.HelpBox("There are no facade designs to show", MessageType.Info);
            return;
        }

        bool hasUnusedFacades = false;
        int unusedIndex = 0;
        //Check all facades have een used and warn if there are unused ones
        for(int i = 0; i < numberOfFacades; i++)
        {
            bool facadeUnused = true;
            foreach(BuildrVolume volume in data.plan.volumes)
            {
                if(volume.ContainsFacade(i))
                {
                    facadeUnused = false;
                    break;
                }
            }
            if(facadeUnused)
            {
                hasUnusedFacades = true;
                unusedIndex = i;
                break;
            }
        }
        if (hasUnusedFacades)
            EditorGUILayout.HelpBox("There are facade designs that are not applied to your building and are unused.\nGo to the Building section to apply them to a facade.\nCheck facade design \""+facades[unusedIndex].name+"\"", MessageType.Warning);

        //Facade Selector
        EditorGUILayout.BeginVertical("box");
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Facade Design:", GUILayout.Width(145));
        string[] facadeNames = new string[numberOfFacades];
        for (int f = 0; f < numberOfFacades; f++)
            facadeNames[f] = facades[f].name;
        selectedFacade = EditorGUILayout.Popup(selectedFacade, facadeNames);
        BuildrFacadeDesign bFacade = facades[selectedFacade];
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();

        if (GUILayout.Button("Add", GUILayout.Width(60)))
        {
            data.facades.Add(new BuildrFacadeDesign("new facade " + numberOfFacades));
            facades = data.facades.ToArray();
            numberOfFacades++;
            selectedFacade = numberOfFacades - 1;
        }

        if (GUILayout.Button("Duplicate", GUILayout.Width(90)))
        {
            data.facades.Add(bFacade.Duplicate());
            facades = data.facades.ToArray();
            numberOfFacades++;
            selectedFacade = numberOfFacades - 1;
        }

        if (GUILayout.Button("Delete", GUILayout.Width(70)))
        {
            if (EditorUtility.DisplayDialog("Deleting Facade Design Entry", "Are you sure you want to delete this facade?", "Delete", "Cancel"))
            {
                data.RemoveFacadeDesign(bFacade);
                selectedFacade = 0;
                GUI.changed = true;

                return;
            }
        }

        if (GUILayout.Button("Import", GUILayout.Width(71)))
        {
            string xmlPath = EditorUtility.OpenFilePanel("Select the XML file...", "Assets/BuildR/Exported/", "xml");
            if (xmlPath == "")
                return;
            BuildrXMLImporter.ImportFacades(xmlPath, _data);
            facades = _data.facades.ToArray();
            selectedFacade = 0;
            GUI.changed = true;
        }

        if (GUILayout.Button("Export", GUILayout.Width(71)))
        {
            string xmlPath = EditorUtility.SaveFilePanel("Export as...", "Assets/BuildR/Exported/", _data.name + "_facadeLibrary", "xml");
            if (xmlPath == "")
                return;
            BuildrXMLExporter.ExportFacades(xmlPath, _data);
            GUI.changed = true;
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();
        EditorGUILayout.EndVertical();

        bFacade = facades[selectedFacade];//reassign
        bFacade.name = EditorGUILayout.TextField("Facade Name: ", bFacade.name);

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Facade Design Type:", GUILayout.Width(145));
        bFacade.type = (BuildrFacadeDesign.types)EditorGUILayout.EnumPopup(bFacade.type);
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Design Type";
            string helpBody = "This allows you to select the type of design you're using.\n" +
                "Simple - the facade openings will be uniform\n" +
                "Patterned - the facade openings will follow a pattern of defined dimensions and textures\n";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        int numberOfTextures = data.textures.Count;
        string[] textureNames = new string[numberOfTextures];
        for (int t = 0; t < numberOfTextures; t++)
            textureNames[t] = data.textures[t].name;

        bFacade.hasWindows = EditorGUILayout.Toggle("Facade Has Bays", bFacade.hasWindows);

        if (bFacade.hasWindows)
        {
            if (bFacade.type == BuildrFacadeDesign.types.simple)
            {
                BuildrBay bbay = bFacade.simpleBay;

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Render Bay", GUILayout.Width(146));
                bool renderBayBack = EditorGUILayout.Toggle(bbay.renderBack);
                if (renderBayBack != bbay.renderBack)
                {
                    bbay.renderBack = renderBayBack;
                }
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Bay Model", GUILayout.Width(146));
                bbay.bayModel = (GameObject)EditorGUILayout.ObjectField(bbay.bayModel, typeof(GameObject), false);
                if (GUILayout.Button("Clear", GUILayout.Width(70)))
                    bbay.bayModel = null;
                EditorGUILayout.EndHorizontal();

                float bbayopeningWidth = Mathf.Max(EditorGUILayout.FloatField("Opening Width", bbay.openingWidth), 0);
                if (bbayopeningWidth != bbay.openingWidth)
                {
                    bbay.openingWidth = bbayopeningWidth;
                }
                float bbayopeningHeight = Mathf.Max(EditorGUILayout.FloatField("Opening Height", bbay.openingHeight), 0);
                if (bbayopeningHeight > data.floorHeight)
                    bbayopeningHeight = data.floorHeight;
                if (bbayopeningHeight != bbay.openingHeight)
                {
                    bbay.openingHeight = bbayopeningHeight;
                }
                float bbayminimumBayWidth = Mathf.Max(EditorGUILayout.FloatField("Min. Spacing", bbay.minimumBayWidth), 0);
                if (bbayminimumBayWidth != bbay.minimumBayWidth)
                {
                    bbay.minimumBayWidth = bbayminimumBayWidth;
                }

                float bbayopeningWidthRatio = EditorGUILayout.Slider("Horizontal Space Ratio", bbay.openingWidthRatio, 0, 1);
                if(bbayopeningWidthRatio != bbay.openingWidthRatio)
                {
                    bbay.openingWidthRatio = bbayopeningWidthRatio;
                }
                float bbayopeningHeightRatio = EditorGUILayout.Slider("Vertical Space Ratio", bbay.openingHeightRatio, 0, 1);
                if (bbayopeningHeightRatio != bbay.openingHeightRatio)
                {
                    bbay.openingHeightRatio = bbayopeningHeightRatio;
                }

                float bbayopeningDepth = EditorGUILayout.Slider("Opening Depth", bbay.openingDepth, -depth, depth);
                if (bbayopeningDepth != bbay.openingDepth)
                {
                    bbay.openingDepth = bbayopeningDepth;
                }
                float bbaycolumnDepth = EditorGUILayout.Slider("Column Depth", bbay.columnDepth, -depth, depth);
                if (bbaycolumnDepth != bbay.columnDepth)
                {
                    bbay.columnDepth = bbaycolumnDepth;
                }
                float bbayrowDepth = EditorGUILayout.Slider("Row Depth", bbay.rowDepth, -depth, depth);
                if (bbayrowDepth != bbay.rowDepth)
                {
                    bbay.rowDepth = bbayrowDepth;
                }
                float bbaycrossDepth = EditorGUILayout.Slider("Cross Depth", bbay.crossDepth, -depth, depth);
                if (bbaycrossDepth != bbay.crossDepth)
                {
                    bbay.crossDepth = bbaycrossDepth;
                }

                int numberOfTextureSlots = bbay.numberOfTextures;
                string[] titles = new string[numberOfTextureSlots];
                for (int bft = 0; bft < numberOfTextureSlots; bft++)
                {
                    titles[bft] = ((BuildrBay.TextureNames)(bft)).ToString();
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Wall Surface:", GUILayout.Width(75));
                editTextureOnFacade = EditorGUILayout.Popup(editTextureOnFacade, titles);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Wall Texture:", GUILayout.Width(75));
                int newFacadeTextureID = EditorGUILayout.Popup(bbay.textureValues[editTextureOnFacade], textureNames);
                if (newFacadeTextureID != bbay.textureValues[editTextureOnFacade])
                {
                    bbay.textureValues[editTextureOnFacade] = newFacadeTextureID;
                }
                EditorGUILayout.EndHorizontal();
                BuildrTexture bTexture = data.textures[bbay.textureValues[editTextureOnFacade]];
                Texture2D texture = bTexture.texture;
                EditorGUILayout.BeginHorizontal();

                if (texture != null)
                    GUILayout.Label(texture, GUILayout.Width(100), GUILayout.Height(100));
                else
                    EditorGUILayout.HelpBox("No texture assigned for '" + textureNames[bbay.textureValues[editTextureOnFacade]] + "', assign one in the Textures menu above", MessageType.Warning);

                bbay.flipValues[editTextureOnFacade] = EditorGUILayout.Toggle("Flip 90\u00B0", bbay.flipValues[editTextureOnFacade]);

                EditorGUILayout.EndHorizontal();
            }
            else
            {
                //Patterned design GUI

                int numberOfBays = bFacade.bayPattern.Count;
                int numberOfBayDesigns = data.bays.Count;

                EditorGUILayout.BeginHorizontal();
                GUILayout.BeginHorizontal("box");
                if (GUILayout.Button("Add New Bay Design"))
                {
                    BuildrBay newBay = new BuildrBay("new bay design " + (numberOfBayDesigns + 1));
                    data.bays.Add(newBay);
                    bFacade.bayPattern.Add(numberOfBayDesigns);
                    numberOfBays++;
                    selectedBayPatternIndex = numberOfBays - 1;
                    numberOfBayDesigns++;
                    GUI.changed = true;
                }
                EditorGUILayout.EndHorizontal();
                if (numberOfBays == 0 || data.bays.Count == 0)
                {
                    EditorGUILayout.HelpBox("There are no bay designs to show", MessageType.Info);
        //                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.EndVertical();
                    return;
                }

                BuildrBay[] bays = new BuildrBay[numberOfBays];
                for (int i = 0; i < numberOfBays; i++)
                {
                    bays[i] = data.bays[bFacade.bayPattern[i]];
                }
                selectedBayPatternIndex = Mathf.Clamp(selectedBayPatternIndex, 0, numberOfBays - 1);

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                GUILayout.BeginHorizontal("box");
                string[] bayDesignNames = new string[data.bays.Count];
                for (int i = 0; i < numberOfBayDesigns; i++)
                {
                    bayDesignNames[i] = data.bays[i].name;
                }
                selectedBayDesign = EditorGUILayout.Popup(selectedBayDesign, bayDesignNames);
                if (GUILayout.Button("Add Selected"))
                {
                    bFacade.bayPattern.Add(selectedBayDesign);
                    GUI.changed = true;
                }
                if (GUILayout.Button("Duplicate Selected"))
                {
                    BuildrBay newBay = data.bays[selectedBayDesign].Duplicate();
                    data.bays.Add(newBay);
                    bFacade.bayPattern.Add(numberOfBayDesigns);
                    numberOfBays++;
                    selectedBayPatternIndex = numberOfBays - 1;
                    numberOfBayDesigns++;
                    GUI.changed = true;
                }
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndHorizontal();

                GUILayout.BeginVertical("box");
                EditorGUILayout.LabelField("Bay Design Order:");
                var scrollbarHStyle = new GUIStyle(GUI.skin.horizontalScrollbar);
                var scrollbarBackStyle = new GUIStyle();
                var scrollbarVStyle = new GUIStyle(GUI.skin.verticalScrollbar);
                scrollbarVStyle.fixedHeight = scrollbarVStyle.fixedWidth = 0;
                bayDesignPatternScrollView = EditorGUILayout.BeginScrollView(bayDesignPatternScrollView, false, false, scrollbarHStyle, scrollbarVStyle, scrollbarBackStyle, GUILayout.Height(40));
                List<string> bayNames = new List<string>();
                foreach (int bayIndex in bFacade.bayPattern)
                {
                    bayNames.Add(data.bays[bayIndex].name);
                }
                selectedBayPatternIndex = GUILayout.Toolbar(selectedBayPatternIndex, bayNames.ToArray());
                EditorGUILayout.EndScrollView();
                BuildrBay bBay = data.bays[bFacade.bayPattern[selectedBayPatternIndex]];

                EditorGUILayout.BeginHorizontal();

                EditorGUI.BeginDisabledGroup(selectedBayPatternIndex == 0);
                if (GUILayout.Button("<<", GUILayout.Width(40)))
                {
                    int bayDesignIndex = bFacade.bayPattern[selectedBayPatternIndex];
                    bFacade.bayPattern.RemoveAt(selectedBayPatternIndex);
                    bFacade.bayPattern.Insert(selectedBayPatternIndex - 1, bayDesignIndex);
                    selectedBayPatternIndex--;
                    GUI.changed = true;
                }
                EditorGUI.EndDisabledGroup();
                if (GUILayout.Button("Remove"))
                {
                    bFacade.bayPattern.RemoveAt(selectedBayPatternIndex);
                    GUI.changed = true;
                }
                if (GUILayout.Button("Delete"))
                {
                    if (EditorUtility.DisplayDialog("Deleting Bay Design Entry", "Are you sure you want to delete this bay?", "Delete", "Cancel"))
                    {
                        int deletedBayDesignIndex = bFacade.bayPattern[selectedBayPatternIndex];
                        Debug.Log("Delete Bay Design " + deletedBayDesignIndex);
                        Debug.Log("Delete Bay Design " + data.bays[deletedBayDesignIndex].name);
                        data.bays.RemoveAt(deletedBayDesignIndex);
                        int numberOfFacadeDesigns = data.facades.Count;
                        for (int i = 0; i < numberOfFacadeDesigns; i++)
                        {
                            BuildrFacadeDesign checkFacade = data.facades[i];
                            int bayPatternSize = checkFacade.bayPattern.Count;
                            for (int j = 0; j < bayPatternSize; j++)
                            {
                                if (checkFacade.bayPattern[j] == deletedBayDesignIndex)
                                {
                                    checkFacade.bayPattern.RemoveAt(j);
                                    j--;
                                    bayPatternSize--;
                                }
                                else if (checkFacade.bayPattern[j] > deletedBayDesignIndex)
                                    checkFacade.bayPattern[j]--;
                            }
                        }
                        GUI.changed = true;
                    }
                }
                EditorGUI.BeginDisabledGroup(selectedBayPatternIndex == numberOfBays - 1);
                if (GUILayout.Button(">>", GUILayout.Width(40)))
                {
                    int bayDesignIndex = bFacade.bayPattern[selectedBayPatternIndex];
                    bFacade.bayPattern.Insert(selectedBayPatternIndex + 2, bayDesignIndex);
                    bFacade.bayPattern.RemoveAt(selectedBayPatternIndex);
                    selectedBayPatternIndex++;
                    GUI.changed = true;
                }
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndVertical();

                GUILayout.Space(10);
                EditorGUILayout.BeginVertical("box");
                bBay.name = EditorGUILayout.TextField("Name: ", bBay.name);
                bool bBayisOpening = EditorGUILayout.Toggle("Has Opening", bBay.isOpening);
                if(bBayisOpening != bBay.isOpening)
                {
                    bBay.isOpening = bBayisOpening;
                }

                bool bBayRenderBack = EditorGUILayout.Toggle("Render Back", bBay.renderBack);
                if (bBayRenderBack != bBay.renderBack)
                {
                    bBay.renderBack = bBayRenderBack;
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Bay Model", GUILayout.Width(146));
                bBay.bayModel = (GameObject)EditorGUILayout.ObjectField(bBay.bayModel, typeof(GameObject), false);
                if (GUILayout.Button("Clear", GUILayout.Width(70)))
                    bBay.bayModel = null;
                EditorGUILayout.EndHorizontal();

                float bBayopeningWidth = Mathf.Max(EditorGUILayout.FloatField("Opening Width", bBay.openingWidth), 0);
                if (bBayopeningWidth != bBay.openingWidth)
                {
                    bBay.openingWidth = bBayopeningWidth;
                }
                float bBayopeningHeight = Mathf.Clamp(EditorGUILayout.FloatField("Opening Height", bBay.openingHeight), 0, data.floorHeight);
                if (bBayopeningHeight != bBay.openingHeight)
                {
                    bBay.openingHeight = bBayopeningHeight;
                }

                float bBayminimumBayWidth = Mathf.Max(EditorGUILayout.FloatField("Bay Spacing Width", bBay.minimumBayWidth), 0);
                if (bBayminimumBayWidth != bBay.minimumBayWidth)
                {
                    bBay.minimumBayWidth = bBayminimumBayWidth;
                }

                float bBayopeningWidthRatio = EditorGUILayout.Slider("Horizontal Space Ratio", bBay.openingWidthRatio, 0, 1);
                if (bBayopeningWidthRatio != bBay.openingWidthRatio)
                {
                    bBay.openingWidthRatio = bBayopeningWidthRatio;
                }
                float bBayopeningHeightRatio = EditorGUILayout.Slider("Vertical Space Ratio", bBay.openingHeightRatio, 0, 1);
                if (bBayopeningHeightRatio != bBay.openingHeightRatio)
                {
                    bBay.openingHeightRatio = bBayopeningHeightRatio;
                }

                float bBayopeningDepth = EditorGUILayout.Slider("Opening Depth", bBay.openingDepth, -depth, depth);
                if (bBayopeningDepth != bBay.openingDepth)
                {
                    bBay.openingDepth = bBayopeningDepth;
                }
                float bBaycolumnDepth = EditorGUILayout.Slider("Column depth", bBay.columnDepth, -depth, depth);
                if (bBaycolumnDepth != bBay.columnDepth)
                {
                    bBay.columnDepth = bBaycolumnDepth;
                }
                float bBayrowDepth = EditorGUILayout.Slider("Row depth", bBay.rowDepth, -depth, depth);
                if (bBayrowDepth != bBay.rowDepth)
                {
                    bBay.rowDepth = bBayrowDepth;
                }
                float bBaycrossDepth = EditorGUILayout.Slider("Cross depth", bBay.crossDepth, -depth, depth);
                if (bBaycrossDepth != bBay.crossDepth)
                {
                    bBay.crossDepth = bBaycrossDepth;
                }

                //BAY TEXTURES

                int numberOfTextureSlots = bBay.numberOfTextures;
                string[] titles = new string[numberOfTextureSlots];
                for (int bft = 0; bft < numberOfTextureSlots; bft++)
                {
                    titles[bft] = ((BuildrBay.TextureNames)(bft)).ToString();
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Surface:", GUILayout.Width(75));
                editTextureOnFacade = EditorGUILayout.Popup(editTextureOnFacade, titles);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Texture:", GUILayout.Width(75));
                bBay.textureValues[editTextureOnFacade] = EditorGUILayout.Popup(bBay.textureValues[editTextureOnFacade], textureNames);
                EditorGUILayout.EndHorizontal();
                BuildrTexture bTexture = data.textures[bBay.textureValues[editTextureOnFacade]];
                Texture2D texture = bTexture.texture;
                EditorGUILayout.BeginHorizontal();

                if (texture != null)
                    GUILayout.Label(texture, GUILayout.Width(100), GUILayout.Height(100));
                else
                    EditorGUILayout.HelpBox("No texture assigned for '" + textureNames[bBay.textureValues[editTextureOnFacade]] + "', assign one in the Textures menu above", MessageType.Warning);

                bFacade.flipValues[editTextureOnFacade] = EditorGUILayout.Toggle("Flip 90\u00B0", bFacade.flipValues[editTextureOnFacade]);

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndVertical();
            }
        }
        else
        {
            editTextureOnFacade = 7;
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Surface:", GUILayout.Width(75));
            EditorGUILayout.LabelField("Wall");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Texture:", GUILayout.Width(75));
            int newFacadeTexture = EditorGUILayout.Popup(bFacade.simpleBay.textureValues[editTextureOnFacade], textureNames);
            if (newFacadeTexture != bFacade.simpleBay.textureValues[editTextureOnFacade])
            {
                bFacade.simpleBay.textureValues[editTextureOnFacade] = newFacadeTexture;
            }
            EditorGUILayout.EndHorizontal();
            BuildrTexture bTexture = data.textures[bFacade.simpleBay.textureValues[editTextureOnFacade]];
            Texture2D texture = bTexture.texture;
            EditorGUILayout.BeginHorizontal();

            if (texture != null)
                GUILayout.Label(texture, GUILayout.Width(100), GUILayout.Height(100));
            else
                EditorGUILayout.HelpBox("No texture assigned for '" + textureNames[bFacade.simpleBay.textureValues[editTextureOnFacade]] + "', assign one in the Textures menu above", MessageType.Warning);

            bFacade.simpleBay.flipValues[editTextureOnFacade] = EditorGUILayout.Toggle("Flip 90\u00B0", bFacade.simpleBay.flipValues[editTextureOnFacade]);

            EditorGUILayout.EndHorizontal();
        }
    }
    private static void GenerateFacades(BuildrData data)
    {
        BuildrGenerateConstraints constraints = data.generatorConstraints;
        RandomGen rgen = constraints.rgen;

        //generate bays
        //blank
        BuildrBay blankBay = new BuildrBay("Blank");
        blankBay.isOpening = false;
        data.bays.Add(blankBay);
        //door
        BuildrBay doorBay = new BuildrBay("Door");
        doorBay.openingHeight = data.floorHeight * 0.9f;
        doorBay.openingHeightRatio = 0.0f;
        float doorWidth = (doorTexture.texture.width / (float)doorTexture.texture.height) * doorBay.openingHeight;
        doorBay.openingWidth = doorWidth;
        doorBay.openingDepth = rgen.OutputRange(0.0f, 0.3f);
        doorBay.SetTexture(BuildrBay.TextureNames.OpeningBackTexture, data.textures.IndexOf(doorTexture));
        data.bays.Add(doorBay);
        //ground window
        BuildrBay groundWindow = new BuildrBay("Ground Window");
        groundWindow.openingWidth = rgen.OutputRange(constraints.openingMinimumWidth, constraints.openingMaximumWidth);
        groundWindow.openingHeight = rgen.OutputRange(constraints.openingMinimumHeight, Mathf.Min(data.floorHeight,constraints.openingMinimumHeight));
        groundWindow.openingDepth = rgen.OutputRange(constraints.openingMinimumDepth, constraints.openingMaximumDepth);
        groundWindow.openingHeightRatio = 0.8f;
        data.bays.Add(groundWindow);

        //        BuildrTexture groundFloorWindowTexture = windowTexture.Duplicate("groundWindowTexture");
        groundFloorWindowTexture.tiled = false;
        groundFloorWindowTexture.tiledX = Mathf.RoundToInt(groundWindow.openingWidth / groundWindow.openingHeight);
        int groundtextureIndex = data.textures.IndexOf(groundFloorWindowTexture);
        //        data.textures.Add(groundFloorWindowTexture);
        groundWindow.SetTexture(BuildrBay.TextureNames.OpeningBackTexture, groundtextureIndex);
        //other windows
        BuildrBay windowBay = new BuildrBay("Window");
        data.bays.Add(windowBay);
        //util window
        BuildrBay utilBay = new BuildrBay("Utility Window");
        data.bays.Add(utilBay);

        //generate facades
        BuildrFacadeDesign basicFacadeDesign = new BuildrFacadeDesign("default");
        basicFacadeDesign.simpleBay.openingWidth = rgen.OutputRange(constraints.openingMinimumWidth, constraints.openingMaximumWidth);
        basicFacadeDesign.simpleBay.openingHeight = rgen.OutputRange(constraints.openingMinimumHeight, Mathf.Min(data.floorHeight, constraints.openingMinimumHeight));
        basicFacadeDesign.simpleBay.openingDepth = rgen.OutputRange(constraints.openingMinimumDepth, constraints.openingMaximumDepth);
        //        float roughBaySize = basicFacadeDesign.simpleBay.openingHeight + basicFacadeDesign.simpleBay.openingWidth;
        basicFacadeDesign.simpleBay.minimumBayWidth = rgen.OutputRange(constraints.minimumBayMaximumWidth,constraints.minimumBayMaximumWidth);
        data.facades.Add(basicFacadeDesign);
        //ground floor with and without door
        BuildrFacadeDesign groundFloorDoor = new BuildrFacadeDesign("Ground Floor With Door");
        groundFloorDoor.type = BuildrFacadeDesign.types.patterned;
        int patternSize = rgen.OutputRange(1, 8);
        for(int i = 0; i < patternSize; i++)
            groundFloorDoor.bayPattern.Add(rgen.output>0.2f?2:0);
        groundFloorDoor.bayPattern.Insert(rgen.OutputRange(0, patternSize), 1);//insert door into pattern
        data.facades.Add(groundFloorDoor);
        //couple of main facades
        //utility/back wall facade
        //maybe attic version

        BuildrPlan plan = data.plan;
        for(int v = 0; v < plan.numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int numberOfFloors = volume.numberOfFloors;
            volume.styles.Clear();
            for(int f = 0; f < volume.points.Count; f++)
            {
                int facadeIndex = volume.points[f];
                volume.styles.AddStyle(0, facadeIndex, numberOfFloors - 1);
                volume.styles.AddStyle(1, facadeIndex, 1);
            }
        }
    }
    private static void GenerateFacades(BuildrData data)
    {
        BuildrGenerateConstraints constraints = data.generatorConstraints;
        RandomGen rgen = constraints.rgen;

        //generate bays
        //blank
        BuildrBay blankBay = new BuildrBay("Blank");

        blankBay.isOpening = false;
        data.bays.Add(blankBay);
        //door
        BuildrBay doorBay = new BuildrBay("Door");

        doorBay.openingHeight      = data.floorHeight * 0.9f;
        doorBay.openingHeightRatio = 0.0f;
        float doorWidth = (doorTexture.texture.width / (float)doorTexture.texture.height) * doorBay.openingHeight;

        doorBay.openingWidth = doorWidth;
        doorBay.openingDepth = rgen.OutputRange(0.0f, 0.3f);
        doorBay.SetTexture(BuildrBay.TextureNames.OpeningBackTexture, data.textures.IndexOf(doorTexture));
        data.bays.Add(doorBay);
        //ground window
        BuildrBay groundWindow = new BuildrBay("Ground Window");

        groundWindow.openingWidth       = rgen.OutputRange(constraints.openingMinimumWidth, constraints.openingMaximumWidth);
        groundWindow.openingHeight      = rgen.OutputRange(constraints.openingMinimumHeight, Mathf.Min(data.floorHeight, constraints.openingMinimumHeight));
        groundWindow.openingDepth       = rgen.OutputRange(constraints.openingMinimumDepth, constraints.openingMaximumDepth);
        groundWindow.openingHeightRatio = 0.8f;
        data.bays.Add(groundWindow);

//        BuildrTexture groundFloorWindowTexture = windowTexture.Duplicate("groundWindowTexture");
        groundFloorWindowTexture.tiled  = false;
        groundFloorWindowTexture.tiledX = Mathf.RoundToInt(groundWindow.openingWidth / groundWindow.openingHeight);
        int groundtextureIndex = data.textures.IndexOf(groundFloorWindowTexture);

//        data.textures.Add(groundFloorWindowTexture);
        groundWindow.SetTexture(BuildrBay.TextureNames.OpeningBackTexture, groundtextureIndex);
        //other windows
        BuildrBay windowBay = new BuildrBay("Window");

        data.bays.Add(windowBay);
        //util window
        BuildrBay utilBay = new BuildrBay("Utility Window");

        data.bays.Add(utilBay);

        //generate facades
        BuildrFacadeDesign basicFacadeDesign = new BuildrFacadeDesign("default");

        basicFacadeDesign.simpleBay.openingWidth  = rgen.OutputRange(constraints.openingMinimumWidth, constraints.openingMaximumWidth);
        basicFacadeDesign.simpleBay.openingHeight = rgen.OutputRange(constraints.openingMinimumHeight, Mathf.Min(data.floorHeight, constraints.openingMinimumHeight));
        basicFacadeDesign.simpleBay.openingDepth  = rgen.OutputRange(constraints.openingMinimumDepth, constraints.openingMaximumDepth);
//        float roughBaySize = basicFacadeDesign.simpleBay.openingHeight + basicFacadeDesign.simpleBay.openingWidth;
        basicFacadeDesign.simpleBay.minimumBayWidth = rgen.OutputRange(constraints.minimumBayMaximumWidth, constraints.minimumBayMaximumWidth);
        data.facades.Add(basicFacadeDesign);
        //ground floor with and without door
        BuildrFacadeDesign groundFloorDoor = new BuildrFacadeDesign("Ground Floor With Door");

        groundFloorDoor.type = BuildrFacadeDesign.types.patterned;
        int patternSize = rgen.OutputRange(1, 8);

        for (int i = 0; i < patternSize; i++)
        {
            groundFloorDoor.bayPattern.Add(rgen.output > 0.2f?2:0);
        }
        groundFloorDoor.bayPattern.Insert(rgen.OutputRange(0, patternSize), 1);//insert door into pattern
        data.facades.Add(groundFloorDoor);
        //couple of main facades
        //utility/back wall facade
        //maybe attic version

        BuildrPlan plan = data.plan;

        for (int v = 0; v < plan.numberOfVolumes; v++)
        {
            BuildrVolume volume         = plan.volumes[v];
            int          numberOfFloors = volume.numberOfFloors;
            volume.styles.Clear();
            for (int f = 0; f < volume.points.Count; f++)
            {
                int facadeIndex = volume.points[f];
                volume.styles.AddStyle(0, facadeIndex, numberOfFloors - 1);
                volume.styles.AddStyle(1, facadeIndex, 1);
            }
        }
    }
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, Rect[] uvConstraints)
    {
        data = _data;
        mesh = _mesh;
        textures = data.textures.ToArray();
        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan plan = data.plan;
        int numberOfVolumes = plan.numberOfVolumes;

        if(plan.numberOfFacades != uvConstraints.Length)
            Debug.LogError("Incompatible amount of uv constraints " + plan.numberOfFacades +" uvc: "+ uvConstraints.Length);

        float largestDepthValue = 0;//deepest value of a bay design in the building
        foreach (BuildrBay bay in data.bays)
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
        foreach (BuildrFacadeDesign facade in data.facades)
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value

        int facadeCount = 0;
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int numberOfVolumePoints = volume.points.Count;
            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;

                int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
                int indexA = f;
                int indexB = (f + 1) % numberOfVolumePoints;
                int indexBP = (f + 2) % numberOfVolumePoints;
                Vector3 p0m = plan.points[volume.points[indexAM]].vector3;
                Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                Vector3 p1 = plan.points[volume.points[indexB]].vector3;
                Vector3 p1p = plan.points[volume.points[indexBP]].vector3;

                facadeCount++;

                float realFadeWidth = Vector3.Distance(p0, p1);
                float facadeWidth = realFadeWidth - largestDepthValue * 2.0f;
                Vector3 facadeDirection = (p1 - p0).normalized;
                Vector3 facadeCross = Vector3.Cross(facadeDirection, Vector3.up).normalized;
                Vector3 lastFacadeDirection = (p0 - p0m).normalized;
                Vector3 nextFacadeDirection = (p1p - p1).normalized;

                //only bother with facade directions when facade may intersect inverted geometry
                float facadeDirDotL = Vector3.Dot(-facadeDirection, lastFacadeDirection);
                float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
                if (facadeDirDotL <= 0 || facadeCrossDotL <= 0) lastFacadeDirection = -facadeCross;

                float facadeDirDotN = Vector3.Dot(-facadeDirection, nextFacadeDirection);
                float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
                if (facadeDirDotN <= 0 || facadeCrossDotN <= 0) nextFacadeDirection = facadeCross;


                int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;
                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                p0 += floorHeightStart;
                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int floorPatternSize = 0;
                List<int> facadePatternReference = new List<int>();//this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int patternCount = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits)//need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                        facadePatternReference.Add(patternCount);
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                float foundationHeight = data.foundationHeight;
                if (foundationHeight > 0 && floorBase == 0)
                {
                    int subMesh = _data.foundationTexture;
                    Vector3 foundationVector = Vector3.up * -foundationHeight;
                    Vector3 w0 = p0 + foundationVector;
                    Vector3 w1 = p1 + foundationVector;
                    Vector3 w2 = p0;
                    Vector3 w3 = p1;
                    AddPlane(w0, w1, w2, w3, subMesh, false, new Vector2(0, -foundationHeight), new Vector2(facadeWidth, 0));
                }

                Vector2 facadeUV = Vector2.zero;

                for (int r = 0; r < rows; r++)
                {
                    bool firstRow = r == 0;
                    bool lastRow = r == (rows - 1);
                    //Get the facade style id
                    //need to loop through the facade designs floor by floor until we get to the right one
                    float currentHeight = floorHeight * r;
                    Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentHeight;
                    int modFloor = (r % floorPatternSize);
                    int modFloorPlus = ((r + 1) % floorPatternSize);
                    int modFloorMinus = (r > 0) ? ((r - 1) % floorPatternSize) : 0;
                    BuildrFacadeDesign lastFacadeDesign = null;
                    BuildrFacadeDesign nextFacadeDesign = null;

                    facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];
                    nextFacadeDesign = data.facades[styleUnits[facadePatternReference[modFloorPlus]].styleID];
                    lastFacadeDesign = data.facades[styleUnits[facadePatternReference[modFloorMinus]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        if(data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                            isBlankWall = true;
                        else
                        {
                            BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                            if (firstBay.openingWidth > facadeWidth) isBlankWall = true;
                            if (facadeDesign.bayPattern.Count == 0) isBlankWall = true;
                        }
                    }
                    else
                    {
                        if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                            isBlankWall = true;
                    }

                    Vector3 windowBase = facadeFloorBaseVector;
                    facadeUV.x = 0;
                    facadeUV.y += currentHeight;
                    if (!isBlankWall)
                    {
                        float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int numberOfBays = 0;
                        BuildrBay[] bayDesignPattern;
                        int numberOfBayDesigns;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bayDesignPattern = new BuildrBay[numberOfBayDesigns];
                            for (int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bayDesignPattern = new[] { facadeDesign.simpleBay };
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while (true)
                        {
                            int patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                            if (patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                                break;
                            it--;
                            if (it < 0)
                                break;
                        }

                        float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                        for (int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;
                            BuildrBay lastBay;
                            BuildrBay nextBay;
                            bool firstColumn = c == 0;
                            bool lastColumn = c == numberOfBays - 1;
                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bayDesignPattern[c % numberOfBayStyles];
                                int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0;
                                lastBay = bayDesignPattern[lastBayIndex];
                                nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles];
                            }
                            else
                            {
                                bayStyle = facadeDesign.simpleBay;
                                lastBay = facadeDesign.simpleBay;
                                nextBay = facadeDesign.simpleBay;
                            }
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftWidth = actualWindowSpacing * bayStyle.openingWidthRatio;
                            float rightWidth = actualWindowSpacing - leftWidth;
                            float openingWidth = bayStyle.openingWidth;

                            if (firstColumn) leftWidth += largestDepthValue;
                            if (lastColumn) rightWidth += largestDepthValue;

                            //                            float openingHeight = bayStyle.openingHeight;
                            BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                            Vector2 columnuvunits = columnTexture.tileUnitUV;
                            float openingHeight = bayStyle.openingHeight;
                            if (columnTexture.patterned) openingHeight = Mathf.Round(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                            //if (bayStyle.openingHeight == floorHeight) bayStyle.openingHeight = floorHeight;

                            float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                            if (columnTexture.patterned) rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;

                            float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight);

                            bool previousBayIdentical = bayStyle == lastBay;
                            bool nextBayIdentical = bayStyle == nextBay;
                            if (previousBayIdentical && !firstColumn)
                                leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount

                            Vector3 w0, w1, w2, w3;
                            float windowSideDepth, bottomDepth;

                            if (!bayStyle.isOpening)
                            {
                                int wallSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.WallTexture);
                                bool wallFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.WallTexture);
                                float bayWidthSize = openingWidth + actualWindowSpacing;
                                if (firstColumn || lastColumn) bayWidthSize += largestDepthValue;
                                Vector3 bayWidth = facadeDirection * bayWidthSize;
                                Vector3 bayHeight = Vector3.up * floorHeight;
                                Vector3 bayDepth = facadeCross * largestDepthValue;
                                w0 = windowBase;
                                w1 = windowBase + bayWidth;
                                w2 = windowBase + bayHeight;
                                w3 = windowBase + bayWidth + bayHeight;
                                Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight);
                                AddPlane(w0, w1, w2, w3, wallSubMesh, wallFlipped, facadeUV, bayOpeningUVEnd);

                                Vector2 UVEnd = new Vector2(1, floorHeight);
                                if (!previousBayIdentical && !firstColumn)//left
                                {
                                    Vector3 wA = w0 + bayDepth;
                                    Vector3 wB = w2 + bayDepth;
                                    AddPlane(w2, wB, w0, wA, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }

                                if (!nextBayIdentical && !lastColumn)//right
                                {
                                    Vector3 wA = w1 + bayDepth;
                                    Vector3 wB = w3 + bayDepth;
                                    AddPlane(w1, wA, w3, wB, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }

                                if (lastFacadeDesign != facadeDesign && !firstRow)//bottom
                                {
                                    Vector3 wA = w0 + ((!firstColumn) ? facadeCross*largestDepthValue : -lastFacadeDirection*largestDepthValue);
                                    Vector3 wB = w1 + ((!lastColumn) ? facadeCross*largestDepthValue : nextFacadeDirection*largestDepthValue);
                                    AddPlane(w0, wA, w1, wB, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }
                                if (nextFacadeDesign != facadeDesign && !lastRow)//top
                                {
                                    Vector3 wA = w2 + ((!firstColumn) ? facadeCross*largestDepthValue : -lastFacadeDirection*largestDepthValue);
                                    Vector3 wB = w3 + ((!lastColumn) ? facadeCross*largestDepthValue : nextFacadeDirection*largestDepthValue);
                                    AddPlane(w3, wB, w2, wA, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }

                                windowBase = w1;//move base vertor to next bay
                                facadeUV.x += bayWidthSize;
                                continue;//bay filled - move onto next bay
                            }

                            var verts = new Vector3[16];
                            verts[0] = windowBase;
                            verts[1] = verts[0] + leftWidth * facadeDirection;
                            verts[2] = verts[1] + openingWidth * facadeDirection;
                            verts[3] = verts[2] + rightWidth * facadeDirection;
                            windowBase = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount
                            facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth;

                            Vector3 rowBottomVector = Vector3.up * rowBottomHeight;
                            verts[4] = verts[0] + rowBottomVector;
                            verts[5] = verts[1] + rowBottomVector;
                            verts[6] = verts[2] + rowBottomVector;
                            verts[7] = verts[3] + rowBottomVector;

                            Vector3 openingVector = Vector3.up * openingHeight;
                            verts[8] = verts[4] + openingVector;
                            verts[9] = verts[5] + openingVector;
                            verts[10] = verts[6] + openingVector;
                            verts[11] = verts[7] + openingVector;

                            Vector3 rowTopVector = Vector3.up * rowTopHeight;
                            verts[12] = verts[8] + rowTopVector;
                            verts[13] = verts[9] + rowTopVector;
                            verts[14] = verts[10] + rowTopVector;
                            verts[15] = verts[11] + rowTopVector;

                            Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth;
                            Vector3 crossDepthVector = facadeCross * bayStyle.crossDepth;
                            Vector3 rowDepthVector = facadeCross * bayStyle.rowDepth;
                            Vector3 columnDepthVector = facadeCross * bayStyle.columnDepth;
                            Vector3 largestDepthVector = facadeCross * largestDepthValue;
                            Vector2 uvStart, uvEnd;

                            int windowSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                            int submeshBottom = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningSillTexture);
                            int submeshTop = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningCeilingTexture);
                            int columnSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                            int crossSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                            int rowSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                            bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                            bool flippedBottom = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningSillTexture);
                            bool flippedTop = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningCeilingTexture);
                            bool columnFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                            bool crossFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                            bool rowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                            int windowBoxSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningSideTexture);
                            bool windowBoxFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningSideTexture);

                            ///WINDOWS
                            w0 = verts[5] + openingDepthVector;
                            w1 = verts[6] + openingDepthVector;
                            w2 = verts[9] + openingDepthVector;
                            w3 = verts[10] + openingDepthVector;
                            Vector2 windowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight);
                            Vector2 windowUVEnd = windowUVStart + new Vector2(openingWidth, openingHeight);
                            if (bayStyle.renderBack && !data.cullBays)
                                AddPlane(w0, w1, w2, w3, windowSubMesh, windowFlipped, windowUVStart, windowUVEnd);

                            //Window Sides
                            w0 = verts[5] + largestDepthVector;
                            w1 = verts[6] + largestDepthVector;
                            w2 = verts[9] + largestDepthVector;
                            w3 = verts[10] + largestDepthVector;
                            windowSideDepth = Mathf.Min(bayStyle.columnDepth, bayStyle.openingDepth) - largestDepthValue;//Window Left
                            float columnDiff = bayStyle.columnDepth - bayStyle.openingDepth;
                            if (data.renderInteriors)//Inner Window Walls
                            {
                                //left
                                uvStart = facadeUV + new Vector2(leftWidth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 leftDepthVector = facadeCross * windowSideDepth;
                                if (firstColumn) leftDepthVector = facadeCross * -largestDepthValue;
                                Vector3 wl0 = w0 + leftDepthVector;
                                Vector3 wl2 = w2 + leftDepthVector;
                                AddPlane(wl0, w0, wl2, w2, windowBoxSubmesh, windowBoxFlipped, uvStart, uvEnd);
                                //right
                                uvStart = facadeUV + new Vector2(leftWidth + openingWidth - windowSideDepth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 rightDepthVector = facadeCross * windowSideDepth;
                                if (lastColumn) rightDepthVector = facadeCross * -largestDepthValue;
                                Vector3 wr1 = w1 + rightDepthVector;
                                Vector3 wr3 = w3 + rightDepthVector;
                                AddPlane(wr3, w3, wr1, w1, windowBoxSubmesh, windowBoxFlipped, uvEnd, uvStart);
                            }

                            if (columnDiff > 0 || !data.renderInteriors)//External Window Sides
                            {
                                //left
                                uvStart = facadeUV + new Vector2(leftWidth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(columnDiff, openingHeight);
                                Vector3 sideDepthVectorA = facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                Vector3 sideDepthVectorB = facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                if (firstColumn) sideDepthVectorA = facadeCross * -largestDepthValue;
                                Vector3 wd0l = w0 + sideDepthVectorA;
                                Vector3 wd1l = w2 + sideDepthVectorA;
                                Vector3 wd2l = w0 + sideDepthVectorB;
                                Vector3 wd3l = w2 + sideDepthVectorB;
                                AddPlane(wd0l, wd2l, wd1l, wd3l, windowBoxSubmesh, windowBoxFlipped, uvStart, uvEnd);
                                //      right                          
                                uvStart = facadeUV + new Vector2(leftWidth + openingWidth - windowSideDepth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                sideDepthVectorA = facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                sideDepthVectorB = facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                if (lastColumn) sideDepthVectorA = facadeCross * -largestDepthValue;
                                Vector3 wd0r = w1 + sideDepthVectorA;
                                Vector3 wd1r = w3 + sideDepthVectorA;
                                Vector3 wd2r = w1 + sideDepthVectorB;
                                Vector3 wd3r = w3 + sideDepthVectorB;
                                AddPlane(wd1r, wd3r, wd0r, wd2r, windowBoxSubmesh, windowBoxFlipped, uvStart, uvEnd);
                            }

                            //Window Row Sides/Sills
                            bottomDepth = Mathf.Min(bayStyle.rowDepth, bayStyle.openingDepth) - largestDepthValue;
                            float rowDiff = bayStyle.rowDepth - bayStyle.openingDepth;
                            if (data.renderInteriors)//Window Sill Interiors
                            {
                                uvStart = new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, bottomDepth);

//                                if (rowBottomHeight > 0)//Bottom
//                                {
                                    Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                    Vector3 wl0 = w0 + bottomDepthVector;
                                    Vector3 wl1 = w1 + bottomDepthVector;
                                    AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                }
//                                if (rowTopHeight > 0)//Top
//                                {
                                    Vector3 topDepthVector = facadeCross * bottomDepth;
                                    Vector3 wl2 = w2 + topDepthVector;
                                    Vector3 wl3 = w3 + topDepthVector;
                                    AddPlane(w2, w3, wl2, wl3, submeshTop, flippedTop, uvStart, uvEnd);
//                                }
                            }

                            if (rowDiff > 0 || !data.renderInteriors)//Window External Sills
                            {
                                uvStart = facadeUV + new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, rowDiff);

//                                if (rowBottomHeight > 0)//Bottom
//                                {
                                    Vector3 wd0l = w0 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd1l = w1 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd2l = w0 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    Vector3 wd3l = w1 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    AddPlane(wd0l, wd1l, wd2l, wd3l, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                }

//                                if (rowTopHeight > 0)//Top
//                                {
                                    Vector3 wd0r = w2 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd1r = w3 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd2r = w2 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    Vector3 wd3r = w3 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    AddPlane(wd1r, wd0r, wd3r, wd2r, submeshTop, flippedTop, uvStart, uvEnd);
//                                }
                            }

                            ///COLUMNS
                            //Column Face
                            if (leftWidth > 0)//Column Face Left
                            {
                                Vector3 leftColumnDepthVector = (!firstColumn) ? columnDepthVector : Vector3.zero;
                                w0 = verts[4] + leftColumnDepthVector;
                                w1 = verts[5] + leftColumnDepthVector;
                                w2 = verts[8] + leftColumnDepthVector;
                                w3 = verts[9] + leftColumnDepthVector;
                                Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight);
                                Vector2 leftColumnUVEnd = leftColumnUVStart + new Vector2(leftWidth, openingHeight);
                                AddPlane(w0, w1, w2, w3, columnSubMesh, columnFlipped, leftColumnUVStart, leftColumnUVEnd);

                                if (!firstColumn)//Left Column Top Bottom
                                {
                                    w0 = verts[4] + largestDepthVector;
                                    w1 = verts[5] + largestDepthVector;
                                    w2 = verts[8] + largestDepthVector;
                                    w3 = verts[9] + largestDepthVector;

                                    bottomDepth = Mathf.Min(bayStyle.crossDepth, bayStyle.columnDepth) - largestDepthValue;
                                    float colDiff = bayStyle.crossDepth - bayStyle.columnDepth;
                                    if (bottomDepth != 0)
                                    {
                                        if (data.renderInteriors)
                                        {
                                            uvStart = new Vector2(0, 0);
                                            uvEnd = uvStart + new Vector2(leftWidth, bottomDepth);
                                            Vector3 bottomDepthVector = facadeCross * bottomDepth;
//                                            if(rowBottomHeight>0)
//                                            {
                                                Vector3 wl0 = w0 + bottomDepthVector;
                                                Vector3 wl1 = w1 + bottomDepthVector;
                                                AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                            }
//                                            if(rowTopHeight > 0)
//                                            {
                                                Vector3 wl2 = w2 + bottomDepthVector;
                                                Vector3 wl3 = w3 + bottomDepthVector;
                                                AddPlane(w2, w3, wl2, wl3, submeshTop, flippedTop, uvStart, uvEnd);
//                                            }
                                        }

                                        if (colDiff > 0 || !data.renderInteriors)
                                        {
                                            uvStart = new Vector2(0, rowBottomHeight);
                                            uvEnd = uvStart + new Vector2(rowDiff, openingHeight);
//                                            if(rowBottomHeight > 0)//Bottom
//                                            {
                                                Vector3 wd0l = w0 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1l = w1 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2l = w0 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3l = w1 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd2l, wd0l, wd3l, wd1l, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                            }
//                                            if(rowTopHeight > 0)//Top
//                                            {
                                                Vector3 wd0r = w2 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1r = w3 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2r = w2 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3r = w3 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd3r, wd1r, wd2r, wd0r, submeshTop, flippedTop, uvStart, uvEnd);
//                                            }
                                        }
                                    }
                                }
                            }
                            if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right
                            {
                                Vector3 rightColumeDepthVector = (!lastColumn) ? columnDepthVector : Vector3.zero;
                                w0 = verts[6] + rightColumeDepthVector;
                                w1 = verts[7] + rightColumeDepthVector;
                                w2 = verts[10] + rightColumeDepthVector;
                                w3 = verts[11] + rightColumeDepthVector;
                                Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight);
                                Vector2 rightColumnUVEnd = rightColumnUVStart + new Vector2(rightWidth, openingHeight);
                                AddPlane(w0, w1, w2, w3, columnSubMesh, columnFlipped, rightColumnUVStart, rightColumnUVEnd);
                                if (!lastColumn)//Right Column Top Bottom
                                {
                                    w0 = verts[6] + largestDepthVector;
                                    w1 = verts[7] + largestDepthVector;
                                    w2 = verts[10] + largestDepthVector;
                                    w3 = verts[11] + largestDepthVector;

                                    bottomDepth = Mathf.Min(bayStyle.crossDepth, bayStyle.columnDepth) - largestDepthValue;//Window Left
                                    float colDiff = bayStyle.crossDepth - bayStyle.columnDepth;
                                    if (bottomDepth != 0)
                                    {
                                        if (data.renderInteriors)
                                        {
                                            uvStart = new Vector2(leftWidth+openingWidth, 0);
                                            uvEnd = uvStart + new Vector2(rightWidth, bottomDepth);
                                            Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                            if (rowBottomHeight > 0)
                                            {
                                                Vector3 wl0 = w0 + bottomDepthVector;
                                                Vector3 wl1 = w1 + bottomDepthVector;
                                                AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                            }
                                            if (rowTopHeight > 0)
                                            {
                                                Vector3 wl2 = w2 + bottomDepthVector;
                                                Vector3 wl3 = w3 + bottomDepthVector;
                                                AddPlane(wl3, wl2, w3, w2, submeshTop, flippedTop, uvStart, uvEnd);
                                            }
                                        }

                                        if (colDiff > 0 || !data.renderInteriors)
                                        {
                                            uvStart = facadeUV + new Vector2(0, rowBottomHeight);
                                            uvEnd = uvStart + new Vector2(rowDiff, openingHeight);
                                            if (rowBottomHeight > 0)//Bottom
                                            {
                                                Vector3 wd0l = w0 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1l = w1 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2l = w0 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3l = w1 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd2l, wd0l, wd3l, wd1l, submeshBottom, flippedBottom, uvStart, uvEnd);
                                            }
                                            if (rowTopHeight > 0)//Top
                                            {
                                                Vector3 wd0r = w2 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1r = w3 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2r = w2 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3r = w3 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd3r, wd1r, wd2r, wd0r, submeshTop, flippedTop, uvStart, uvEnd);
                                            }
                                        }
                                    }
                                }
                            }

                            ///ROWS
                            //Row Bottom
                            w0 = verts[1] + rowDepthVector;
                            w1 = verts[2] + rowDepthVector;
                            w2 = verts[5] + rowDepthVector;
                            w3 = verts[6] + rowDepthVector;
                            if (rowBottomHeight > 0)
                            {
                                Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0);
                                Vector2 bottomRowUVEnd = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight);
                                AddPlane(w0, w1, w2, w3, rowSubMesh, rowFlipped, bottomRowUVStart, bottomRowUVEnd);

                                //Row Sides
                                w0 = verts[1] + largestDepthVector;
                                w1 = verts[2] + largestDepthVector;
                                w2 = verts[5] + largestDepthVector;
                                w3 = verts[6] + largestDepthVector;
                                uvStart = facadeUV + new Vector2(0, 0);
                                uvEnd = uvStart + new Vector2(largestDepthValue, rowBottomHeight);
                                if (leftWidth > 0)//Left Side
                                {
                                    Vector3 sideDepthVectorA = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorB = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if(firstColumn)
                                    {
                                        sideDepthVectorA = facadeCross * -largestDepthValue;
                                    }
//                                    uvEnd.x = largestDepthValue;//Vector3.Distance(sideDepthVectorA, sideDepthVectorB);
//                                    uvEnd.y = Vector3.Distance(sideDepthVectorA,sideDepthVectorB);
                                    Vector3 wd0l = w0 + sideDepthVectorA;
                                    Vector3 wd1l = w2 + sideDepthVectorA;
                                    Vector3 wd2l = w0 + sideDepthVectorB;
                                    Vector3 wd3l = w2 + sideDepthVectorB;
                                    AddPlane(wd0l, wd2l, wd1l, wd3l, rowSubMesh, rowFlipped, uvStart, uvEnd);
                                }

//                                if (rightWidth > 0)//Right Side
//                                {
                                    Vector3 sideDepthVectorC = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorD = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if (lastColumn) sideDepthVectorC = facadeCross * -largestDepthValue;
                                    Vector3 wd0r = w1 + sideDepthVectorC;
                                    Vector3 wd1r = w3 + sideDepthVectorC;
                                    Vector3 wd2r = w1 + sideDepthVectorD;
                                    Vector3 wd3r = w3 + sideDepthVectorD;
                                    AddPlane(wd1r, wd3r, wd0r, wd2r, rowSubMesh, rowFlipped, uvStart, uvEnd);
//                                }
                            }

                            //Row Top
                            w0 = verts[9] + rowDepthVector;
                            w1 = verts[10] + rowDepthVector;
                            w2 = verts[13] + rowDepthVector;
                            w3 = verts[14] + rowDepthVector;

                            if (rowTopHeight > 0)
                            {
                                Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight);
                                Vector2 topRowUVEnd = topRowUVStart + new Vector2(openingWidth, rowTopHeight);
                                AddPlane(w0, w1, w2, w3, rowSubMesh, rowFlipped, topRowUVStart, topRowUVEnd);

                                //Row Sides
                                w0 = verts[9] + largestDepthVector;
                                w1 = verts[10] + largestDepthVector;
                                w2 = verts[13] + largestDepthVector;
                                w3 = verts[14] + largestDepthVector;
                                uvStart = facadeUV + new Vector2(0, rowBottomHeight+openingHeight);
                                uvEnd = uvStart + new Vector2(largestDepthValue, rowTopHeight);
                                if (leftWidth > 0)//Left Side
                                {
                                    Vector3 sideDepthVectorA = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorB = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if (firstColumn) sideDepthVectorA = facadeCross * -largestDepthValue;
                                    Vector3 wd0l = w0 + sideDepthVectorA;
                                    Vector3 wd1l = w2 + sideDepthVectorA;
                                    Vector3 wd2l = w0 + sideDepthVectorB;
                                    Vector3 wd3l = w2 + sideDepthVectorB;
                                    AddPlane(wd0l, wd2l, wd1l, wd3l, rowSubMesh, rowFlipped, uvStart, uvEnd);
                                }

//                                if (rightWidth > 0)//Right Side
//                                {
                                    Vector3 sideDepthVectorC = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorD = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if (lastColumn) sideDepthVectorC = facadeCross * -largestDepthValue;
                                    Vector3 wd0r = w1 + sideDepthVectorC;
                                    Vector3 wd1r = w3 + sideDepthVectorC;
                                    Vector3 wd2r = w1 + sideDepthVectorD;
                                    Vector3 wd3r = w3 + sideDepthVectorD;
                                    AddPlane(wd1r, wd3r, wd0r, wd2r, rowSubMesh, rowFlipped, uvStart, uvEnd);
//                                }
                            }

                            //Cross Left Bottom
                            Vector3 leftCrossDepthVector = (!firstColumn) ? crossDepthVector : Vector3.zero;
                            w0 = verts[0] + leftCrossDepthVector;
                            w1 = verts[1] + leftCrossDepthVector;
                            w2 = verts[4] + leftCrossDepthVector;
                            w3 = verts[5] + leftCrossDepthVector;
                            Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0);
                            Vector2 crossLBUVEnd = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossLBUVStart, crossLBUVEnd);
                           
                            //Cross Left Top
                            if (rowTopHeight > 0)
                            {
                                w0 = verts[8] + leftCrossDepthVector;
                                w1 = verts[9] + leftCrossDepthVector;
                                w2 = verts[12] + leftCrossDepthVector;
                                w3 = verts[13] + leftCrossDepthVector;
                                Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight);
                                Vector2 crossLTUVEnd = crossLTUVStart + new Vector2(leftWidth, rowTopHeight);
                                AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossLTUVStart, crossLTUVEnd);
                            }

                            if ((!nextBayIdentical || lastColumn) && rightWidth > 0)
                            {
                                if(lastColumn) crossDepthVector = Vector3.zero;//zero the ends of buildings
                                //Cross Right Bottom
                                w0 = verts[2] + crossDepthVector;
                                w1 = verts[3] + crossDepthVector;
                                w2 = verts[6] + crossDepthVector;
                                w3 = verts[7] + crossDepthVector;
                                Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                                Vector2 crossRBUVEnd = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight);
                                AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossRBUVStart, crossRBUVEnd);

                                //Cross Right Top
                                if (rowTopHeight > 0)
                                {
                                    w0 = verts[10] + crossDepthVector;
                                    w1 = verts[11] + crossDepthVector;
                                    w2 = verts[14] + crossDepthVector;
                                    w3 = verts[15] + crossDepthVector;
                                    Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight);
                                    Vector2 crossRTUVEnd = crossRTUVStart + new Vector2(rightWidth, rowTopHeight);
                                    AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossRTUVStart, crossRTUVEnd);
                                }
                            }

                            ///FACADE BOTTOMS
                            if (lastFacadeDesign != facadeDesign && rowBottomHeight > 0)
                            {
                                //Row Bottom
                                w0 = verts[1] + largestDepthVector;
                                w1 = verts[2] + largestDepthVector;

                                bottomDepth = bayStyle.rowDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, bottomDepth);

                                Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                Vector3 wl0 = w0 + bottomDepthVector;
                                Vector3 wl1 = w1 + bottomDepthVector;
                                AddPlane(w0, w1, wl0, wl1, submeshBottom, flippedBottom, uvStart, uvEnd);

                                if(!firstColumn)
                                {
                                    //Left Cross Bottom
                                    w0 = verts[0] + largestDepthVector;
                                    w1 = verts[1] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(leftWidth, bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(w0, w1, wl0, wl1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }

                                //Right Cross Bottom
                                if ((!nextBayIdentical && !lastColumn) && rightWidth > 0)
                                {
                                    w0 = verts[2] + largestDepthVector;
                                    w1 = verts[3] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                                    uvEnd = uvStart + new Vector2(rightWidth, bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(w0, w1, wl0, wl1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }
                            }


                            ///FACADE TOPS
                            if (nextFacadeDesign != facadeDesign && rowTopHeight > 0)
                            {
                                //Row Top
                                w0 = verts[13] + largestDepthVector;
                                w1 = verts[14] + largestDepthVector;

                                bottomDepth = bayStyle.rowDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, bottomDepth);

                                Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                Vector3 wl0 = w0 + bottomDepthVector;
                                Vector3 wl1 = w1 + bottomDepthVector;
                                AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);

                                //Left Cross Top
                                if (!firstColumn)
                                {
                                    w0 = verts[12] + largestDepthVector;
                                    w1 = verts[13] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(leftWidth,bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }

                                //Right Cross Top
                                if ((!nextBayIdentical && !lastColumn) && rightWidth > 0)
                                {
                                    w0 = verts[14] + largestDepthVector;
                                    w1 = verts[15] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(leftWidth+openingWidth, 0);
                                    uvEnd = uvStart + new Vector2(rightWidth, bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }
                            }

                            ///BAY SIDES
                            // LEFT
                            if(!previousBayIdentical)
                            {
                                //Column
                                w1 = verts[4] + largestDepthVector;
                                w3 = verts[8] + largestDepthVector;
                                windowSideDepth = bayStyle.columnDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 depthVector = facadeCross * windowSideDepth;
                                Vector3 wr1 = w1 + depthVector;
                                Vector3 wr3 = w3 + depthVector;
                                AddPlane(wr3, w3, wr1, w1, columnSubMesh, columnFlipped, uvStart, uvEnd);

                                //Cross Bottom
                                w1 = verts[0] + largestDepthVector;
                                w3 = verts[4] + largestDepthVector;
                                windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, 0);
                                uvEnd = uvStart + new Vector2(windowSideDepth, rowBottomHeight);
                                depthVector = facadeCross * windowSideDepth;
                                wr1 = w1 + depthVector;
                                wr3 = w3 + depthVector;
                                AddPlane(wr3, w3, wr1, w1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                //Cross Top
                                if (rowTopHeight > 0)
                                {
                                    w1 = verts[8] + largestDepthVector;
                                    w3 = verts[12] + largestDepthVector;
                                    windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(windowSideDepth, rowTopHeight);
                                    depthVector = facadeCross * windowSideDepth;
                                    wr1 = w1 + depthVector;
                                    wr3 = w3 + depthVector;
                                    AddPlane(wr3, w3, wr1, w1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                }
                            }

                            //RIGHT
                            if (!nextBayIdentical && !lastColumn)
                            {
                                //Column Sides
                                w1 = verts[7] + largestDepthVector;
                                w3 = verts[11] + largestDepthVector;
                                windowSideDepth = bayStyle.columnDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 depthVector = facadeCross * windowSideDepth;
                                Vector3 wr1 = w1 + depthVector;
                                Vector3 wr3 = w3 + depthVector;
                                AddPlane(w3, wr3, w1, wr1, columnSubMesh, columnFlipped, uvStart, uvEnd);

                                //Cross Bottom
                                w1 = verts[3] + largestDepthVector;
                                w3 = verts[7] + largestDepthVector;
                                windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, 0);
                                uvEnd = uvStart + new Vector2(windowSideDepth, rowBottomHeight);
                                depthVector = facadeCross * windowSideDepth;
                                wr1 = w1 + depthVector;
                                wr3 = w3 + depthVector;
                                AddPlane(w3, wr3, w1, wr1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                //Cross Top
                                if (rowTopHeight > 0)
                                {
                                    w1 = verts[11] + largestDepthVector;
                                    w3 = verts[15] + largestDepthVector;
                                    windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(windowSideDepth, rowTopHeight);
                                    depthVector = facadeCross * windowSideDepth;
                                    wr1 = w1 + depthVector;
                                    wr3 = w3 + depthVector;
                                    AddPlane(w3, wr3, w1, wr1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                }
                            }
                        }
                    }
                    else
                    {
                        // windowless wall
                        Vector3 wallVector = (facadeDirection * (facadeWidth+largestDepthValue*2.0f));
                        Vector3 wallHeightVector = Vector3.up * floorHeight;
                        Vector3 w0 = facadeFloorBaseVector;
                        Vector3 w1 = facadeFloorBaseVector + wallVector;
                        Vector3 w2 = facadeFloorBaseVector + wallHeightVector;
                        Vector3 w3 = facadeFloorBaseVector + wallVector + wallHeightVector;
                        int wallSubmesh = facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture);
                        bool flipped = facadeDesign.simpleBay.IsFlipped(BuildrBay.TextureNames.WallTexture);
                        Vector2 wallUVStart = facadeUV;
                        Vector2 wallUVEnd = facadeUV + new Vector2(realFadeWidth, floorHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd);//face

                        if (nextFacadeDesign.hasWindows && !lastRow)
                        {
                            Vector3 wl2 = w2 - lastFacadeDirection*largestDepthValue;
                            Vector3 wl3 = w3 + nextFacadeDirection*largestDepthValue;
                            Vector2 uvEnd = new Vector2(facadeWidth, 1);
                            AddPlane(w3, wl3, w2, wl2, wallSubmesh, flipped, wallUVStart, uvEnd);//top
                        }
                    }
                }
            }
            //Bottom of the mesh - it's mostly to ensure the model can render certain shadows correctly
            if (data.drawUnderside)
            {
                Vector3 foundationDrop = Vector3.down * data.foundationHeight;
                var newEndVerts = new Vector3[numberOfVolumePoints];
                var newEndUVs = new Vector2[numberOfVolumePoints];
                for (int i = 0; i < numberOfVolumePoints; i++)
                {
                    newEndVerts[i] = plan.points[volume.points[i]].vector3 + foundationDrop;
                    newEndUVs[i] = Vector2.zero;
                }
                var tris = new List<int>(data.plan.GetTrianglesBySectorBase(v));
                tris.Reverse();
                int bottomSubMesh = facadeDesign.GetTexture(BuildrFacadeDesign.textureNames.columnTexture);
                mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), bottomSubMesh);
            }
        }
        data = null;
        mesh = null;
        textures = null;
    }
Exemple #9
0
    public static bool UpgradeData(BuildrData data)
    {
        float currentVersion = BuildrVersion.NUMBER;
        float dataVersion    = data.versionNumber;

        if (currentVersion == dataVersion)
        {
            //The data matches the current version of Buildr - do nothing.
            return(true);
        }

        if (currentVersion < dataVersion)
        {
            Debug.LogError("BuildR v." + currentVersion + ": Great scot! This data is from the future! (version:" + dataVersion + ") - need to avoid contact to ensure the survival of the universe...");
            return(false);//don't touch ANYTHING!
        }

        Debug.Log("BuildR v." + currentVersion + " Upgrading the data from version " + dataVersion + " to version " + currentVersion + "\nRemember to backup your data!");

        if (dataVersion < 0.7f)
        {
            //upgrade the facade data so we use BuildrBay design elements
            int facadeDesignCount = data.facades.Count;
            for (int i = 0; i < facadeDesignCount; i++)
            {
                BuildrFacadeDesign design = data.facades[i];
                if (!design.alternatingSpacing)
                {
                    design.type = BuildrFacadeDesign.types.simple;
                    design.simpleBay.isOpening          = design.hasWindows;
                    design.simpleBay.openingWidth       = design.windowWidth;
                    design.simpleBay.openingHeight      = design.windowHeight;
                    design.simpleBay.minimumBayWidth    = design.minimumWindowSpacing;
                    design.simpleBay.openingWidthRatio  = 0.5f;
                    design.simpleBay.openingHeightRatio = design.windowHeightRatio;
                    design.simpleBay.openingDepth       = design.windowDepth;
                    design.simpleBay.columnDepth        = design.columnDepth;
                    design.simpleBay.rowDepth           = design.rowDepth;
                    design.simpleBay.crossDepth         = design.crossDepth;

                    design.simpleBay.textureValues[0] = design.textureValues[4]; //openingBackTexture,
                    design.simpleBay.textureValues[1] = design.textureValues[5]; //openingSideTexture,
                    design.simpleBay.textureValues[2] = design.textureValues[6]; //openingSillTexture,
                    design.simpleBay.textureValues[3] = design.textureValues[7]; //openingCeilingTexture,
                    design.simpleBay.textureValues[4] = design.textureValues[0]; //columnTexture,
                    design.simpleBay.textureValues[5] = design.textureValues[1]; //rowTexture,
                    design.simpleBay.textureValues[6] = design.textureValues[2]; //crossTexture,
                    design.simpleBay.textureValues[7] = design.textureValues[0]; //wallTexture

                    design.simpleBay.flipValues[0] = design.flipValues[4];       //openingBackTexture,
                    design.simpleBay.flipValues[1] = design.flipValues[5];       //openingSideTexture,
                    design.simpleBay.flipValues[2] = design.flipValues[6];       //openingSillTexture,
                    design.simpleBay.flipValues[3] = design.flipValues[7];       //openingCeilingTexture,
                    design.simpleBay.flipValues[4] = design.flipValues[0];       //columnTexture,
                    design.simpleBay.flipValues[5] = design.flipValues[1];       //rowTexture,
                    design.simpleBay.flipValues[6] = design.flipValues[2];       //crossTexture,
                    design.simpleBay.flipValues[7] = design.flipValues[0];       //wallTexture
                }
                else
                {
                    design.type = BuildrFacadeDesign.types.patterned;
                    float     alternateSpacerRatio = (1 / (1 + (1 / design.minimumWindowSpacingAlt)));
                    BuildrBay bayA = new BuildrBay(design.name + "a");
                    bayA.isOpening          = design.hasWindows;
                    bayA.openingWidth       = design.windowWidth;
                    bayA.openingHeight      = design.windowHeight;
                    bayA.minimumBayWidth    = design.minimumWindowSpacing;
                    bayA.openingWidthRatio  = 1 - alternateSpacerRatio;
                    bayA.openingHeightRatio = design.windowHeightRatio;
                    bayA.openingDepth       = design.windowDepth;
                    bayA.columnDepth        = design.columnDepth;
                    bayA.rowDepth           = design.rowDepth;
                    bayA.crossDepth         = design.crossDepth;

                    bayA.textureValues[0] = design.textureValues[4]; //openingBackTexture,
                    bayA.textureValues[1] = design.textureValues[5]; //openingSideTexture,
                    bayA.textureValues[2] = design.textureValues[6]; //openingSillTexture,
                    bayA.textureValues[3] = design.textureValues[7]; //openingCeilingTexture,
                    bayA.textureValues[4] = design.textureValues[0]; //columnTexture,
                    bayA.textureValues[5] = design.textureValues[1]; //rowTexture,
                    bayA.textureValues[6] = design.textureValues[2]; //crossTexture,
                    bayA.textureValues[7] = design.textureValues[0]; //wallTexture
                    bayA.flipValues[0]    = design.flipValues[4];    //openingBackTexture,
                    bayA.flipValues[1]    = design.flipValues[5];    //openingSideTexture,
                    bayA.flipValues[2]    = design.flipValues[6];    //openingSillTexture,
                    bayA.flipValues[3]    = design.flipValues[7];    //openingCeilingTexture,
                    bayA.flipValues[4]    = design.flipValues[0];    //columnTexture,
                    bayA.flipValues[5]    = design.flipValues[1];    //rowTexture,
                    bayA.flipValues[6]    = design.flipValues[2];    //crossTexture,
                    bayA.flipValues[7]    = design.flipValues[0];    //wallTexture

                    BuildrBay bayB = new BuildrBay(design.name + "b");
                    bayB.isOpening          = design.hasWindows;
                    bayB.openingWidth       = design.windowWidth;
                    bayB.openingHeight      = design.windowHeight;
                    bayB.minimumBayWidth    = design.minimumWindowSpacing;
                    bayB.openingWidthRatio  = alternateSpacerRatio;
                    bayB.openingHeightRatio = design.windowHeightRatio;
                    bayB.openingDepth       = design.windowDepth;
                    bayB.columnDepth        = design.columnDepth;
                    bayB.rowDepth           = design.rowDepth;
                    bayB.crossDepth         = design.crossDepth;

                    bayB.textureValues[0] = design.textureValues[4]; //openingBackTexture,
                    bayB.textureValues[1] = design.textureValues[5]; //openingSideTexture,
                    bayB.textureValues[2] = design.textureValues[6]; //openingSillTexture,
                    bayB.textureValues[3] = design.textureValues[7]; //openingCeilingTexture,
                    bayB.textureValues[4] = design.textureValues[0]; //columnTexture,
                    bayB.textureValues[5] = design.textureValues[1]; //rowTexture,
                    bayB.textureValues[6] = design.textureValues[2]; //crossTexture,
                    bayB.textureValues[7] = design.textureValues[0]; //wallTexture
                    bayB.flipValues[0]    = design.flipValues[4];    //openingBackTexture,
                    bayB.flipValues[1]    = design.flipValues[5];    //openingSideTexture,
                    bayB.flipValues[2]    = design.flipValues[6];    //openingSillTexture,
                    bayB.flipValues[3]    = design.flipValues[7];    //openingCeilingTexture,
                    bayB.flipValues[4]    = design.flipValues[0];    //columnTexture,
                    bayB.flipValues[5]    = design.flipValues[1];    //rowTexture,
                    bayB.flipValues[6]    = design.flipValues[2];    //crossTexture,
                    bayB.flipValues[7]    = design.flipValues[0];    //wallTexture

                    int bayIndex = data.bays.Count;
                    data.bays.Add(bayA);
                    data.bays.Add(bayB);
                    design.bayPattern.Clear();
                    design.bayPattern.Add(bayIndex);
                    design.bayPattern.Add(bayIndex + 1);
                }
            }
        }

        if (dataVersion < 0.9f)
        {
            //new details addition
            data.details = new List <BuildrDetail>();

            //update Volume to account for the new array of Render bools
            BuildrPlan plan = data.plan;
            foreach (BuildrVolume volume in plan.volumes)
            {
                int volumeSize = volume.points.Count;
                for (int i = 0; i < volumeSize; i++)
                {
                    volume.renderFacade.Add(true);
                }
            }
        }


        if (dataVersion < 1.0f)
        {
            foreach (BuildrBay bay in data.bays)
            {
                bay.renderBack = true;
            }
        }

        data.versionNumber = BuildrVersion.NUMBER;//update the data version number once upgrade is complete
        return(true);
    }
Exemple #10
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex)
    {
        data      = _data;
        mesh      = _mesh;
        mesh.name = "Interior Mesh Volume " + volumeIndex;
        textures  = data.textures.ToArray();

        if (!data.renderInteriors)
        {
            return;
        }

        float largestDepthValue = 0;//deepest value of a bay design in the building
        float tallestBay        = 0;

        foreach (BuildrBay bay in data.bays)
        {
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
            tallestBay        = Mathf.Max(tallestBay, bay.openingHeight + (data.floorHeight - bay.openingHeight) * bay.openingHeightRatio);
        }
        foreach (BuildrFacadeDesign facade in data.facades)
        {
            if (facade.type != BuildrFacadeDesign.types.simple)
            {
                continue;
            }
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value
            if (facade.simpleBay.isOpening)
            {
                tallestBay = Mathf.Max(tallestBay, facade.simpleBay.openingHeight + (data.floorHeight - facade.simpleBay.openingHeight) * facade.simpleBay.openingHeightRatio);
            }
        }


        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan         plan         = data.plan;
        BuildrVolume       volume       = plan.volumes[volumeIndex];
        int     numberOfFloors          = volume.numberOfFloors;
        float   floorHeight             = data.floorHeight;
        Vector3 floorHeightVector       = Vector3.up * floorHeight;
        float   ceilingHeight           = tallestBay + (floorHeight - tallestBay) * data.interiorCeilingHeight;

        //Calculate the internal floor plan points
        int numberOfVolumePoints = volume.points.Count;

        Vector2z[] interiorVolumePoints = new Vector2z[numberOfVolumePoints];
        for (int i = 0; i < numberOfVolumePoints; i++)
        {
            Vector3 lastPoint = plan.points[volume.points[(i > 0) ? i - 1 : numberOfVolumePoints - 1]].vector3;
            Vector3 thisPoint = plan.points[volume.points[i]].vector3;
            Vector3 nextPoint = plan.points[volume.points[(i + 1) % numberOfVolumePoints]].vector3;
            Vector3 normalA   = Vector3.Cross(thisPoint - lastPoint, Vector3.up).normalized;
            Vector3 normalB   = Vector3.Cross(nextPoint - thisPoint, Vector3.up).normalized;

            Vector2z facadeALine = new Vector2z(thisPoint - lastPoint);
            Vector2z facadeBLine = new Vector2z(thisPoint - nextPoint);
            //Calculate facade inner origins for floors
            Vector3  facadeOriginV3A        = lastPoint + normalA * largestDepthValue;
            Vector3  facadeOriginV3B        = nextPoint + normalB * largestDepthValue;
            Vector2z facadeOriginA          = new Vector2z(facadeOriginV3A);
            Vector2z facadeOriginB          = new Vector2z(facadeOriginV3B);
            Vector2z facadeLineIntersection = BuildrUtils.FindIntersection(facadeALine, facadeOriginA, facadeBLine, facadeOriginB);

            interiorVolumePoints[i] = facadeLineIntersection;
        }
        List <Vector2z> interiorVolumePointList = new List <Vector2z>(interiorVolumePoints);
        List <Rect>     volumeCores             = new List <Rect>();
        List <int>      linkedPoints            = new List <int>();

        foreach (Rect core in plan.cores)
        {
            Vector2z coreCenter = new Vector2z(core.center);
            if (BuildrUtils.PointInsidePoly(coreCenter, interiorVolumePoints))
            {
                volumeCores.Add(core);
            }
        }
        int  numberOfVolumeCores = volumeCores.Count;
        bool print = plan.volumes.IndexOf(volume) == 3;

        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            int        numberOfInteriorPoints = interiorVolumePointList.Count;
            Rect       coreBounds             = volumeCores[c];
            Vector2z   coreCenter             = new Vector2z(coreBounds.center);
            Vector2z   coreBL = new Vector2z(coreBounds.xMin, coreBounds.yMin);
            Vector2z   coreBR = new Vector2z(coreBounds.xMax, coreBounds.yMin);
            Vector2z   coreTL = new Vector2z(coreBounds.xMin, coreBounds.yMax);
            Vector2z   coreTR = new Vector2z(coreBounds.xMax, coreBounds.yMax);
            Vector2z[] corePointArray;
            corePointArray = new[] { coreBL, coreBR, coreTR, coreTL };
            //Find the nearest legal cut we can make to join the core and interior point poly
            int   connectingPoint         = -1;
            float connectingPointDistance = Mathf.Infinity;
            for (int p = 0; p < numberOfInteriorPoints; p++)
            {
                if (linkedPoints.Contains(p))
                {
                    continue;
                }
                Vector2z thisPoint         = interiorVolumePointList[p];
                float    thisPointDistance = Vector2z.SqrMag(thisPoint, coreCenter);
                if (thisPointDistance < connectingPointDistance)
                {
                    bool legalCut = true;
                    for (int pc = 0; pc < numberOfInteriorPoints; pc++)
                    {
                        Vector2z p0 = interiorVolumePointList[pc];
                        Vector2z p1 = interiorVolumePointList[(pc + 1) % numberOfInteriorPoints];
                        if (BuildrUtils.FastLineIntersection(coreCenter, thisPoint, p0, p1))//check against all lines that this new cut doesn't intersect
                        {
                            if (print)
                            {
                                Debug.Log("FLI " + pc + " " + coreCenter + " " + thisPoint + " " + p0 + " " + p1);
                            }
                            legalCut = false;
                            break;
                        }
                    }
                    if (legalCut)
                    {
                        connectingPoint         = p;
                        connectingPointDistance = thisPointDistance;
                    }
                }
            }
            if (connectingPoint == -1)
            {
                Debug.Log("Buildr Could not place core");
                continue;
            }
            Vector2z chosenPoint                 = interiorVolumePointList[connectingPoint];
            int      connectingCorePoint         = 0;
            float    connectingCorePointDistance = Mathf.Infinity; // Vector2z.SqrMag(corePointArray[0], chosenPoint);
            for (int cp = 0; cp < 4; cp++)                         //find the core point to make the cut
            {
                float thisCorePointDistance = Vector2z.SqrMag(corePointArray[cp], chosenPoint);
                if (thisCorePointDistance < connectingCorePointDistance)
                {
                    connectingCorePoint         = cp;
                    connectingCorePointDistance = thisCorePointDistance;
                }
            }
            interiorVolumePointList.Insert(connectingPoint, chosenPoint); //loop back on the floorplan to close it
            for (int acp = 0; acp < 5; acp++)                             //loop back on itself to close the core
            {
                interiorVolumePointList.Insert(connectingPoint + 1, corePointArray[(connectingCorePoint + acp) % 4]);
            }
            for (int i = 0; i < linkedPoints.Count; i++)
            {
                if (linkedPoints[i] > connectingPoint)
                {
                    linkedPoints[i] += 7;
                }
            }
            linkedPoints.AddRange(new[] { connectingPoint, connectingPoint + 1, connectingPoint + 2, connectingPoint + 3, connectingPoint + 4, connectingPoint + 5, connectingPoint + 6 });
//            linkedPoints.AddRange(new []{connectingPoint,connectingPoint+6});
        }
//        if(linkedPoints.Count > 0)
//        Debug.Log(linkedPoints.Count+" "+linkedPoints[0]);
        Vector2z[] interiorPointListCore = interiorVolumePointList.ToArray();

        for (int f = 0; f < numberOfVolumePoints; f++)
        {
            ///WALLS

            int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
            int indexA  = f;
            int indexB  = (f + 1) % numberOfVolumePoints;
            int indexBP = (f + 2) % numberOfVolumePoints;

            Vector3 p0m        = plan.points[volume.points[indexAM]].vector3;
            Vector3 p0         = plan.points[volume.points[indexA]].vector3;
            Vector3 p1         = plan.points[volume.points[indexB]].vector3;
            Vector3 p1p        = plan.points[volume.points[indexBP]].vector3;
            Vector3 p0interior = interiorVolumePoints[indexA].vector3;
            Vector3 p1interior = interiorVolumePoints[indexB].vector3;

            float   facadeWidth         = Vector3.Distance(p0, p1) - largestDepthValue * 2.0f;
            Vector3 facadeDirection     = (p1 - p0).normalized;
            Vector3 facadeCross         = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 lastFacadeDirection = (p0 - p0m).normalized;
            Vector3 nextFacadeDirection = (p1p - p1).normalized;

            //only bother with facade directions when facade may intersect inverted geometry
            float facadeDirDotL   = Vector3.Dot(-facadeDirection, lastFacadeDirection);
            float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
            if (facadeDirDotL <= 0 || facadeCrossDotL <= 0)
            {
                lastFacadeDirection = -facadeCross;
            }

            float facadeDirDotN   = Vector3.Dot(-facadeDirection, nextFacadeDirection);
            float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
            if (facadeDirDotN <= 0 || facadeCrossDotN <= 0)
            {
                nextFacadeDirection = facadeCross;
            }


            int floorBase = plan.GetFacadeFloorHeight(volumeIndex, volume.points[indexA], volume.points[indexB]);
            BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
            int        floorPatternSize         = 0;
            List <int> facadePatternReference   = new List <int>();  //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
            int        patternCount             = 0;
            foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them
            {
                floorPatternSize += styleUnit.floors;
                for (int i = 0; i < styleUnit.floors; i++)
                {
                    facadePatternReference.Add(patternCount);
                }
                patternCount++;
            }
            facadePatternReference.Reverse();

            int rows = numberOfFloors;


            Vector2 facadeUV = Vector2.zero;

            for (int r = 0; r < rows; r++)
            {
                float   currentFloorHeight       = floorHeight * r;
                Vector3 currentFloorHeightVector = Vector3.up * (data.floorHeight * r);
                Vector3 facadeFloorBaseVector    = p0 + Vector3.up * currentFloorHeight;
                Vector3 ceilingVector            = Vector3.up * ceilingHeight;
                if (r < floorBase)
                {
                    //no facade rendered
                    //facade gap filler

                    //interior gap points
                    Vector3 i0 = p1 - facadeDirection.normalized * largestDepthValue;
                    Vector3 i1 = p0 + facadeDirection.normalized * largestDepthValue;

                    Vector3 w0  = i0 + currentFloorHeightVector;
                    Vector3 w1  = i1 + currentFloorHeightVector;
                    Vector3 w2  = w0 + facadeCross * largestDepthValue;
                    Vector3 w3  = w1 + facadeCross * largestDepthValue;
                    Vector3 w4  = w0 + ceilingVector;
                    Vector3 w5  = w1 + ceilingVector;
                    Vector3 w6  = w2 + ceilingVector;
                    Vector3 w7  = w3 + ceilingVector;
                    Vector3 w8  = p1interior + currentFloorHeightVector;
                    Vector3 w9  = p0interior + currentFloorHeightVector;
                    Vector3 w10 = w8 + ceilingVector;
                    Vector3 w11 = w9 + ceilingVector;

                    //floor
                    AddData(new[] { w0, w1, w2, w3 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.FloorTexture(r), false);

                    //ceiling
                    AddData(new[] { w5, w4, w7, w6 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.CeilingTexture(r), false);

                    //sides
                    int wallSubmesh = volume.WallTexture(r);
                    AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));
                    AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));

                    //other gaps
                    float uvWidth1 = Vector3.Distance(w2, w8);
                    AddPlane(w2, w8, w6, w10, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth1, floorHeight));
                    float uvWidth2 = Vector3.Distance(w3, w9);
                    AddPlane(w9, w3, w11, w7, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth2, floorHeight));

                    continue;
                }

                //Get the facade style id
                //need to loop through the facade designs floor by floor until we get to the right one
                int modFloor = ((r - floorBase) % floorPatternSize);

                facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                bool isBlankWall = !facadeDesign.hasWindows;
                if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                {
                    if (data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                    {
                        data.illegal = true;
                        return;
                    }

                    BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                    if (firstBay.openingWidth > facadeWidth)
                    {
                        isBlankWall = true;
                    }
                    if (facadeDesign.bayPattern.Count == 0)
                    {
                        isBlankWall = true;
                    }
                }
                else
                {
                    if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                    {
                        isBlankWall = true;
                    }
                }

                if (!isBlankWall)
                {
                    float       patternSize  = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                    int         numberOfBays = 0;
                    BuildrBay[] bayDesignPattern;
                    int         numberOfBayDesigns;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        numberOfBayDesigns = facadeDesign.bayPattern.Count;
                        bayDesignPattern   = new BuildrBay[numberOfBayDesigns];
                        for (int i = 0; i < numberOfBayDesigns; i++)
                        {
                            bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                        }
                    }
                    else
                    {
                        bayDesignPattern   = new[] { facadeDesign.simpleBay };
                        numberOfBayDesigns = 1;
                    }
                    //start with first window width - we'll be adding to this until we have filled the facade width
                    int it = 100;
                    while (true)
                    {
                        int   patternModIndex = numberOfBays % numberOfBayDesigns;
                        float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                        if (patternSize + patternAddition < facadeWidth)
                        {
                            patternSize += patternAddition;
                            numberOfBays++;
                        }
                        else
                        {
                            break;
                        }
                        it--;
                        if (it < 0)
                        {
                            break;
                        }
                    }

                    Vector3 windowBase = facadeFloorBaseVector;
                    facadeUV.x  = 0;
                    facadeUV.y += floorHeight;
                    float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                    for (int c = 0; c < numberOfBays; c++)
                    {
                        BuildrBay bayStyle;
                        BuildrBay lastBay;
                        BuildrBay nextBay;
                        bool      firstColumn = c == 0;
                        bool      lastColumn  = c == numberOfBays - 1;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            int numberOfBayStyles = facadeDesign.bayPattern.Count;
                            bayStyle = bayDesignPattern[c % numberOfBayStyles];
                            int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0;
                            lastBay = bayDesignPattern[lastBayIndex];
                            nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles];
                        }
                        else
                        {
                            bayStyle = facadeDesign.simpleBay;
                            lastBay  = facadeDesign.simpleBay;
                            nextBay  = facadeDesign.simpleBay;
                        }
                        float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                        float leftWidth           = actualWindowSpacing * bayStyle.openingWidthRatio;
                        float rightWidth          = actualWindowSpacing - leftWidth;
                        float openingWidth        = bayStyle.openingWidth;

                        if (firstColumn)
                        {
                            leftWidth += largestDepthValue;
                        }
                        if (lastColumn)
                        {
                            rightWidth += largestDepthValue;
                        }

                        BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                        Vector2       columnuvunits = columnTexture.tileUnitUV;
                        float         openingHeight = bayStyle.openingHeight;
                        if (columnTexture.patterned)
                        {
                            openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                        }
                        if (bayStyle.openingHeight == floorHeight)
                        {
                            bayStyle.openingHeight = floorHeight;
                        }

                        float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                        if (columnTexture.patterned)
                        {
                            rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;
                        }

                        float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight);

                        bool previousBayIdentical = bayStyle == lastBay;
                        bool nextBayIdentical     = bayStyle == nextBay;
                        if (previousBayIdentical && !firstColumn)
                        {
                            leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount
                        }
                        Vector3 w0, w1, w2, w3;

                        int  wallSubmesh = volume.WallTexture(r);
                        bool wallFlipped = false;
                        if (!bayStyle.isOpening)
                        {
                            float bayWidthSize = openingWidth + actualWindowSpacing;
                            if (firstColumn || lastColumn)
                            {
                                bayWidthSize += largestDepthValue;
                            }
                            Vector3 bayWidth  = facadeDirection * bayWidthSize;
                            Vector3 bayHeight = Vector3.up * floorHeight;
                            Vector3 bayDepth  = facadeCross * largestDepthValue;
                            w0 = windowBase + bayDepth;
                            w1 = windowBase + bayWidth + bayDepth;
                            w2 = windowBase + bayHeight + bayDepth;
                            w3 = windowBase + bayWidth + bayHeight + bayDepth;
                            Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, facadeUV, bayOpeningUVEnd);

                            windowBase  = windowBase + bayWidth; //move base vertor to next bay
                            facadeUV.x += openingWidth + actualWindowSpacing;
                            continue;                            //bay filled - move onto next bay
                        }

                        var verts = new Vector3[16];
                        verts[0]    = windowBase;
                        verts[1]    = verts[0] + leftWidth * facadeDirection;
                        verts[2]    = verts[1] + openingWidth * facadeDirection;
                        verts[3]    = verts[2] + rightWidth * facadeDirection;
                        windowBase  = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount
                        facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth;

                        Vector3 rowBottomVector = Vector3.up * rowBottomHeight;
                        verts[4] = verts[0] + rowBottomVector;
                        verts[5] = verts[1] + rowBottomVector;
                        verts[6] = verts[2] + rowBottomVector;
                        verts[7] = verts[3] + rowBottomVector;

                        Vector3 openingVector = Vector3.up * openingHeight;
                        verts[8]  = verts[4] + openingVector;
                        verts[9]  = verts[5] + openingVector;
                        verts[10] = verts[6] + openingVector;
                        verts[11] = verts[7] + openingVector;

                        Vector3 rowTopVector = Vector3.up * rowTopHeight;
                        verts[12] = verts[8] + rowTopVector;
                        verts[13] = verts[9] + rowTopVector;
                        verts[14] = verts[10] + rowTopVector;
                        verts[15] = verts[11] + rowTopVector;

                        //Realign facade end points
                        if (firstColumn)
                        {
                            verts[0]  = p0interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[4]  = verts[0] + rowBottomVector;
                            verts[8]  = verts[4] + openingVector;
                            verts[12] = verts[8] + rowTopVector;
                        }

                        if (lastColumn)
                        {
                            verts[3]  = p1interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[7]  = verts[3] + rowBottomVector;
                            verts[11] = verts[7] + openingVector;
                            verts[15] = verts[11] + rowTopVector;
                        }

                        Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth;
                        Vector3 wallDepthVecotr    = facadeCross * largestDepthValue;

                        ///WINDOWS
                        int  windowSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                        bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                        w0 = verts[10] + openingDepthVector;
                        w1 = verts[9] + openingDepthVector;
                        w2 = verts[6] + openingDepthVector;
                        w3 = verts[5] + openingDepthVector;
                        Vector2 windowUVStart = new Vector2(0, 0);
                        Vector2 windowUVEnd   = new Vector2(openingWidth, openingHeight);
                        if (bayStyle.renderBack && !data.cullBays)
                        {
                            AddPlane(w0, w1, w2, w3, windowSubmesh, windowFlipped, windowUVStart, windowUVEnd);
                        }

                        ///COLUMNS
                        //Column Face
                        if (leftWidth > 0)//Column Face Left
                        {
                            w0 = verts[4] + wallDepthVecotr;
                            w1 = verts[5] + wallDepthVecotr;
                            w2 = verts[8] + wallDepthVecotr;
                            w3 = verts[9] + wallDepthVecotr;
                            Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight);
                            Vector2 leftColumnUVEnd   = leftColumnUVStart + new Vector2(leftWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, leftColumnUVStart, leftColumnUVEnd);
                        }
                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right
                        {
                            w0 = verts[6] + wallDepthVecotr;
                            w1 = verts[7] + wallDepthVecotr;
                            w2 = verts[10] + wallDepthVecotr;
                            w3 = verts[11] + wallDepthVecotr;
                            Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight);
                            Vector2 rightColumnUVEnd   = rightColumnUVStart + new Vector2(rightWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, rightColumnUVStart, rightColumnUVEnd);
                        }
                        ///ROWS
                        //Row Bottom
                        if (rowBottomHeight > 0)
                        {
                            w0 = verts[1] + wallDepthVecotr;
                            w1 = verts[2] + wallDepthVecotr;
                            w2 = verts[5] + wallDepthVecotr;
                            w3 = verts[6] + wallDepthVecotr;
                            Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0);
                            Vector2 bottomRowUVEnd   = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, bottomRowUVStart, bottomRowUVEnd);
                        }
                        //Row Top
                        if (rowTopHeight > 0)
                        {
                            w0 = verts[9] + wallDepthVecotr;
                            w1 = verts[10] + wallDepthVecotr;
                            w2 = verts[13] + wallDepthVecotr;
                            w3 = verts[14] + wallDepthVecotr;
                            Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight);
                            Vector2 topRowUVEnd   = topRowUVStart + new Vector2(openingWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, topRowUVStart, topRowUVEnd);
                        }

                        //Cross Left Bottom
                        w0 = verts[0] + wallDepthVecotr;
                        w1 = verts[1] + wallDepthVecotr;
                        w2 = verts[4] + wallDepthVecotr;
                        w3 = verts[5] + wallDepthVecotr;
                        Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0);
                        Vector2 crossLBUVEnd   = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLBUVStart, crossLBUVEnd);

                        //Cross Left Top
                        w0 = verts[8] + wallDepthVecotr;
                        w1 = verts[9] + wallDepthVecotr;
                        w2 = verts[12] + wallDepthVecotr;
                        w3 = verts[13] + wallDepthVecotr;
                        Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight);
                        Vector2 crossLTUVEnd   = crossLTUVStart + new Vector2(leftWidth, rowTopHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLTUVStart, crossLTUVEnd);

                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)
                        {
                            //Cross Right Bottom
                            w0 = verts[2] + wallDepthVecotr;
                            w1 = verts[3] + wallDepthVecotr;
                            w2 = verts[6] + wallDepthVecotr;
                            w3 = verts[7] + wallDepthVecotr;
                            Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                            Vector2 crossRBUVEnd   = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRBUVStart, crossRBUVEnd);

                            //Cross Right Top
                            w0 = verts[10] + wallDepthVecotr;
                            w1 = verts[11] + wallDepthVecotr;
                            w2 = verts[14] + wallDepthVecotr;
                            w3 = verts[15] + wallDepthVecotr;
                            Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight);
                            Vector2 crossRTUVEnd   = crossRTUVStart + new Vector2(rightWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRTUVStart, crossRTUVEnd);
                        }
                    }
                }
                else
                {
                    // windowless wall
                    Vector3 interiorStart = p0interior + currentFloorHeightVector;
                    Vector3 interiorEnd   = p1interior + currentFloorHeightVector;
                    //                        Vector3 wallVector = (facadeDirection * facadeWidth);
                    Vector3       wallHeightVector = Vector3.up * floorHeight;
                    Vector3       w0      = interiorStart;
                    Vector3       w1      = interiorEnd;
                    Vector3       w2      = interiorStart + wallHeightVector;
                    Vector3       w3      = interiorEnd + wallHeightVector;
                    BuildrTexture texture = textures[facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture)];
                    var           uvSize  = new Vector2(facadeWidth * (1.0f / texture.textureUnitSize.x), floorHeight * (1.0f / texture.textureUnitSize.y));
                    Vector2       uvunits = texture.tileUnitUV;
                    uvSize.x = Mathf.Ceil(uvSize.x / uvunits.x) * uvunits.x;
                    uvSize.y = Mathf.Ceil(uvSize.y / uvunits.y) * uvunits.y;
                    int     wallSubmesh = 0;
                    bool    flipped     = false;
                    Vector2 wallUVStart = facadeUV;
                    Vector2 wallUVEnd   = facadeUV + new Vector2(facadeWidth, floorHeight);
                    AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd);
                }
            }
        }

        ///FLOORS AND CEILING
        int numberOfBasements   = volume.numberOfBasementFloors;
        int numberOfFloorPoints = interiorVolumePoints.Length;

        int[]   baseFloorPlanTriangles = EarClipper.Triangulate(interiorVolumePoints);
        int     baseFloorVectors       = interiorVolumePoints.Length;
        var     newEndVerts            = new Vector3[baseFloorVectors];
        Vector3 basementBaseDrop       = -floorHeightVector * numberOfBasements;

        for (int i = 0; i < baseFloorVectors; i++)
        {
            newEndVerts[i] = interiorVolumePoints[i].vector3 + basementBaseDrop;
        }
        var tris = new List <int>(baseFloorPlanTriangles);

        //Bottom Floor
        int floorSubmesh = volume.FloorTexture(-numberOfBasements);

        AddData(newEndVerts, baseFloorPlanTriangles, floorSubmesh, false);

        //Top Ceiling
        if (true)//Todo: add conditional for roof opening
        {
            Vector3 ceilingHeightVector = floorHeightVector * (numberOfFloors - 1 + numberOfBasements) + Vector3.up * ceilingHeight;
            for (int i = 0; i < baseFloorVectors; i++)
            {
                newEndVerts[i] += ceilingHeightVector;
            }
            tris.Reverse();
            AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(numberOfFloors - 1), false);
        }

        //inner floors
        int[] floorPlanTriangles   = EarClipper.Triangulate(interiorPointListCore);
        int   numberOfFloorVectors = interiorPointListCore.Length;

        for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors; floorIndex++)
        {
            Vector3 floorVectorHeight = floorHeightVector * floorIndex;
            newEndVerts = new Vector3[numberOfFloorVectors];
            for (int i = 0; i < numberOfFloorVectors; i++)
            {
                newEndVerts[i] = interiorPointListCore[i].vector3 + floorVectorHeight;
            }
            tris = new List <int>(floorPlanTriangles);

            //Floor
            if (floorIndex > -numberOfBasements)
            {
                AddData(newEndVerts, tris.ToArray(), volume.FloorTexture(floorIndex), false);
            }

            //Ceiling
            if (floorIndex < numberOfFloors - 1)
            {
                Vector3 ceilingHeightVector = Vector3.up * ceilingHeight;
                for (int i = 0; i < numberOfFloorVectors; i++)
                {
                    newEndVerts[i] += ceilingHeightVector;
                }
                tris.Reverse();
                AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(floorIndex), false);
            }

            //basement walls
            if (floorIndex < 0)
            {
                for (int f = 0; f < numberOfFloorPoints; f++)
                {
                    Vector3 basementVector = floorHeightVector * floorIndex;
                    int     indexA         = f;
                    int     indexB         = (f + 1) % numberOfFloorPoints;

                    Vector3 p0  = interiorVolumePoints[indexA].vector3 + basementVector;
                    Vector3 p1  = interiorVolumePoints[indexB].vector3 + basementVector;
                    Vector3 p2  = p0 + floorHeightVector;
                    Vector3 p3  = p1 + floorHeightVector;
                    Vector2 uv1 = new Vector2(Vector3.Distance(p0, p1), floorHeight);
                    AddPlane(p0, p1, p2, p3, volume.WallTexture(floorIndex), false, Vector2.zero, uv1);
                }
            }
        }

        //Core walls
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            Rect    coreBounds = volumeCores[c];
            Vector3 coreBL     = new Vector3(coreBounds.xMin, 0, coreBounds.yMin);
            Vector3 coreBR     = new Vector3(coreBounds.xMax, 0, coreBounds.yMin);
            Vector3 coreTL     = new Vector3(coreBounds.xMin, 0, coreBounds.yMax);
            Vector3 coreTR     = new Vector3(coreBounds.xMax, 0, coreBounds.yMax);

            for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors - 1; floorIndex++)
            {
                Vector3 c0        = floorHeightVector * floorIndex + Vector3.up * ceilingHeight;
                Vector3 f0        = floorHeightVector * floorIndex + Vector3.up * floorHeight;
                float   gapHeight = floorHeight - ceilingHeight;
                AddPlane(coreBL + c0, coreBR + c0, coreBL + f0, coreBR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreBR + c0, coreTR + c0, coreBR + f0, coreTR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTR + c0, coreTL + c0, coreTR + f0, coreTL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTL + c0, coreBL + c0, coreTL + f0, coreBL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
            }
        }
    }
Exemple #11
0
    public static void InspectorGUI(BuildrEditMode editMode, BuildrData _data)
    {
        int helpWidth = 20;

        data = _data;

        Undo.RecordObject(data, "Facade Modified");

        BuildrFacadeDesign[] facades = data.facades.ToArray();
        int numberOfFacades          = facades.Length;

        selectedFacade = Mathf.Clamp(selectedFacade, 0, numberOfFacades - 1);

        if (numberOfFacades == 0)
        {
            EditorGUILayout.HelpBox("There are no facade designs to show", MessageType.Info);
            return;
        }

        bool hasUnusedFacades = false;
        int  unusedIndex      = 0;

        //Check all facades have een used and warn if there are unused ones
        for (int i = 0; i < numberOfFacades; i++)
        {
            bool facadeUnused = true;
            foreach (BuildrVolume volume in data.plan.volumes)
            {
                if (volume.ContainsFacade(i))
                {
                    facadeUnused = false;
                    break;
                }
            }
            if (facadeUnused)
            {
                hasUnusedFacades = true;
                unusedIndex      = i;
                break;
            }
        }
        if (hasUnusedFacades)
        {
            EditorGUILayout.HelpBox("There are facade designs that are not applied to your building and are unused.\nGo to the Building section to apply them to a facade.\nCheck facade design \"" + facades[unusedIndex].name + "\"", MessageType.Warning);
        }

        //Facade Selector
        EditorGUILayout.BeginVertical("box");
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Facade Design:", GUILayout.Width(145));
        string[] facadeNames = new string[numberOfFacades];
        for (int f = 0; f < numberOfFacades; f++)
        {
            facadeNames[f] = facades[f].name;
        }
        selectedFacade = EditorGUILayout.Popup(selectedFacade, facadeNames);
        BuildrFacadeDesign bFacade = facades[selectedFacade];

        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();

        if (GUILayout.Button("Add", GUILayout.Width(60)))
        {
            data.facades.Add(new BuildrFacadeDesign("new facade " + numberOfFacades));
            facades = data.facades.ToArray();
            numberOfFacades++;
            selectedFacade = numberOfFacades - 1;
        }

        if (GUILayout.Button("Duplicate", GUILayout.Width(90)))
        {
            data.facades.Add(bFacade.Duplicate());
            facades = data.facades.ToArray();
            numberOfFacades++;
            selectedFacade = numberOfFacades - 1;
        }

        if (GUILayout.Button("Delete", GUILayout.Width(70)))
        {
            if (EditorUtility.DisplayDialog("Deleting Facade Design Entry", "Are you sure you want to delete this facade?", "Delete", "Cancel"))
            {
                data.RemoveFacadeDesign(bFacade);
                selectedFacade = 0;
                GUI.changed    = true;

                return;
            }
        }

        if (GUILayout.Button("Import", GUILayout.Width(71)))
        {
            string xmlPath = EditorUtility.OpenFilePanel("Select the XML file...", "Assets/BuildR/Exported/", "xml");
            if (xmlPath == "")
            {
                return;
            }
            BuildrXMLImporter.ImportFacades(xmlPath, _data);
            facades        = _data.facades.ToArray();
            selectedFacade = 0;
            GUI.changed    = true;
        }

        if (GUILayout.Button("Export", GUILayout.Width(71)))
        {
            string xmlPath = EditorUtility.SaveFilePanel("Export as...", "Assets/BuildR/Exported/", _data.name + "_facadeLibrary", "xml");
            if (xmlPath == "")
            {
                return;
            }
            BuildrXMLExporter.ExportFacades(xmlPath, _data);
            GUI.changed = true;
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();
        EditorGUILayout.EndVertical();

        bFacade      = facades[selectedFacade];//reassign
        bFacade.name = EditorGUILayout.TextField("Facade Name: ", bFacade.name);


        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Facade Design Type:", GUILayout.Width(145));
        bFacade.type = (BuildrFacadeDesign.types)EditorGUILayout.EnumPopup(bFacade.type);
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Design Type";
            string helpBody  = "This allows you to select the type of design you're using.\n" +
                               "Simple - the facade openings will be uniform\n" +
                               "Patterned - the facade openings will follow a pattern of defined dimensions and textures\n";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        int numberOfTextures = data.textures.Count;

        string[] textureNames = new string[numberOfTextures];
        for (int t = 0; t < numberOfTextures; t++)
        {
            textureNames[t] = data.textures[t].name;
        }

        bFacade.hasWindows = EditorGUILayout.Toggle("Facade Has Bays", bFacade.hasWindows);

        if (bFacade.hasWindows)
        {
            if (bFacade.type == BuildrFacadeDesign.types.simple)
            {
                BuildrBay bbay = bFacade.simpleBay;

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Render Bay", GUILayout.Width(146));
                bool renderBayBack = EditorGUILayout.Toggle(bbay.renderBack);
                if (renderBayBack != bbay.renderBack)
                {
                    bbay.renderBack = renderBayBack;
                }
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Bay Model", GUILayout.Width(146));
                bbay.bayModel = (GameObject)EditorGUILayout.ObjectField(bbay.bayModel, typeof(GameObject), false);
                if (GUILayout.Button("Clear", GUILayout.Width(70)))
                {
                    bbay.bayModel = null;
                }
                EditorGUILayout.EndHorizontal();

                float bbayopeningWidth = Mathf.Max(EditorGUILayout.FloatField("Opening Width", bbay.openingWidth), 0);
                if (bbayopeningWidth != bbay.openingWidth)
                {
                    bbay.openingWidth = bbayopeningWidth;
                }
                float bbayopeningHeight = Mathf.Max(EditorGUILayout.FloatField("Opening Height", bbay.openingHeight), 0);
                if (bbayopeningHeight > data.floorHeight)
                {
                    bbayopeningHeight = data.floorHeight;
                }
                if (bbayopeningHeight != bbay.openingHeight)
                {
                    bbay.openingHeight = bbayopeningHeight;
                }
                float bbayminimumBayWidth = Mathf.Max(EditorGUILayout.FloatField("Min. Spacing", bbay.minimumBayWidth), 0);
                if (bbayminimumBayWidth != bbay.minimumBayWidth)
                {
                    bbay.minimumBayWidth = bbayminimumBayWidth;
                }

                float bbayopeningWidthRatio = EditorGUILayout.Slider("Horizontal Space Ratio", bbay.openingWidthRatio, 0, 1);
                if (bbayopeningWidthRatio != bbay.openingWidthRatio)
                {
                    bbay.openingWidthRatio = bbayopeningWidthRatio;
                }
                float bbayopeningHeightRatio = EditorGUILayout.Slider("Vertical Space Ratio", bbay.openingHeightRatio, 0, 1);
                if (bbayopeningHeightRatio != bbay.openingHeightRatio)
                {
                    bbay.openingHeightRatio = bbayopeningHeightRatio;
                }

                float bbayopeningDepth = EditorGUILayout.Slider("Opening Depth", bbay.openingDepth, -depth, depth);
                if (bbayopeningDepth != bbay.openingDepth)
                {
                    bbay.openingDepth = bbayopeningDepth;
                }
                float bbaycolumnDepth = EditorGUILayout.Slider("Column Depth", bbay.columnDepth, -depth, depth);
                if (bbaycolumnDepth != bbay.columnDepth)
                {
                    bbay.columnDepth = bbaycolumnDepth;
                }
                float bbayrowDepth = EditorGUILayout.Slider("Row Depth", bbay.rowDepth, -depth, depth);
                if (bbayrowDepth != bbay.rowDepth)
                {
                    bbay.rowDepth = bbayrowDepth;
                }
                float bbaycrossDepth = EditorGUILayout.Slider("Cross Depth", bbay.crossDepth, -depth, depth);
                if (bbaycrossDepth != bbay.crossDepth)
                {
                    bbay.crossDepth = bbaycrossDepth;
                }

                int      numberOfTextureSlots = bbay.numberOfTextures;
                string[] titles = new string[numberOfTextureSlots];
                for (int bft = 0; bft < numberOfTextureSlots; bft++)
                {
                    titles[bft] = ((BuildrBay.TextureNames)(bft)).ToString();
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Wall Surface:", GUILayout.Width(75));
                editTextureOnFacade = EditorGUILayout.Popup(editTextureOnFacade, titles);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Wall Texture:", GUILayout.Width(75));
                int newFacadeTextureID = EditorGUILayout.Popup(bbay.textureValues[editTextureOnFacade], textureNames);
                if (newFacadeTextureID != bbay.textureValues[editTextureOnFacade])
                {
                    bbay.textureValues[editTextureOnFacade] = newFacadeTextureID;
                }
                EditorGUILayout.EndHorizontal();
                BuildrTexture bTexture = data.textures[bbay.textureValues[editTextureOnFacade]];
                Texture2D     texture  = bTexture.texture;
                EditorGUILayout.BeginHorizontal();

                if (texture != null)
                {
                    GUILayout.Label(texture, GUILayout.Width(100), GUILayout.Height(100));
                }
                else
                {
                    EditorGUILayout.HelpBox("No texture assigned for '" + textureNames[bbay.textureValues[editTextureOnFacade]] + "', assign one in the Textures menu above", MessageType.Warning);
                }

                bbay.flipValues[editTextureOnFacade] = EditorGUILayout.Toggle("Flip 90\u00B0", bbay.flipValues[editTextureOnFacade]);

                EditorGUILayout.EndHorizontal();
            }
            else
            {
                //Patterned design GUI

                int numberOfBays       = bFacade.bayPattern.Count;
                int numberOfBayDesigns = data.bays.Count;

                EditorGUILayout.BeginHorizontal();
                GUILayout.BeginHorizontal("box");
                if (GUILayout.Button("Add New Bay Design"))
                {
                    BuildrBay newBay = new BuildrBay("new bay design " + (numberOfBayDesigns + 1));
                    data.bays.Add(newBay);
                    bFacade.bayPattern.Add(numberOfBayDesigns);
                    numberOfBays++;
                    selectedBayPatternIndex = numberOfBays - 1;
                    numberOfBayDesigns++;
                    GUI.changed = true;
                }
                EditorGUILayout.EndHorizontal();
                if (numberOfBays == 0 || data.bays.Count == 0)
                {
                    EditorGUILayout.HelpBox("There are no bay designs to show", MessageType.Info);
//                    EditorGUILayout.EndHorizontal();
                    EditorGUILayout.EndVertical();
                    return;
                }

                BuildrBay[] bays = new BuildrBay[numberOfBays];
                for (int i = 0; i < numberOfBays; i++)
                {
                    bays[i] = data.bays[bFacade.bayPattern[i]];
                }
                selectedBayPatternIndex = Mathf.Clamp(selectedBayPatternIndex, 0, numberOfBays - 1);

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                GUILayout.BeginHorizontal("box");
                string[] bayDesignNames = new string[data.bays.Count];
                for (int i = 0; i < numberOfBayDesigns; i++)
                {
                    bayDesignNames[i] = data.bays[i].name;
                }
                selectedBayDesign = EditorGUILayout.Popup(selectedBayDesign, bayDesignNames);
                if (GUILayout.Button("Add Selected"))
                {
                    bFacade.bayPattern.Add(selectedBayDesign);
                    GUI.changed = true;
                }
                if (GUILayout.Button("Duplicate Selected"))
                {
                    BuildrBay newBay = data.bays[selectedBayDesign].Duplicate();
                    data.bays.Add(newBay);
                    bFacade.bayPattern.Add(numberOfBayDesigns);
                    numberOfBays++;
                    selectedBayPatternIndex = numberOfBays - 1;
                    numberOfBayDesigns++;
                    GUI.changed = true;
                }
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndHorizontal();

                GUILayout.BeginVertical("box");
                EditorGUILayout.LabelField("Bay Design Order:");
                var scrollbarHStyle    = new GUIStyle(GUI.skin.horizontalScrollbar);
                var scrollbarBackStyle = new GUIStyle();
                var scrollbarVStyle    = new GUIStyle(GUI.skin.verticalScrollbar);
                scrollbarVStyle.fixedHeight = scrollbarVStyle.fixedWidth = 0;
                bayDesignPatternScrollView  = EditorGUILayout.BeginScrollView(bayDesignPatternScrollView, false, false, scrollbarHStyle, scrollbarVStyle, scrollbarBackStyle, GUILayout.Height(40));
                List <string> bayNames = new List <string>();
                foreach (int bayIndex in bFacade.bayPattern)
                {
                    bayNames.Add(data.bays[bayIndex].name);
                }
                selectedBayPatternIndex = GUILayout.Toolbar(selectedBayPatternIndex, bayNames.ToArray());
                EditorGUILayout.EndScrollView();
                BuildrBay bBay = data.bays[bFacade.bayPattern[selectedBayPatternIndex]];

                EditorGUILayout.BeginHorizontal();

                EditorGUI.BeginDisabledGroup(selectedBayPatternIndex == 0);
                if (GUILayout.Button("<<", GUILayout.Width(40)))
                {
                    int bayDesignIndex = bFacade.bayPattern[selectedBayPatternIndex];
                    bFacade.bayPattern.RemoveAt(selectedBayPatternIndex);
                    bFacade.bayPattern.Insert(selectedBayPatternIndex - 1, bayDesignIndex);
                    selectedBayPatternIndex--;
                    GUI.changed = true;
                }
                EditorGUI.EndDisabledGroup();
                if (GUILayout.Button("Remove"))
                {
                    bFacade.bayPattern.RemoveAt(selectedBayPatternIndex);
                    GUI.changed = true;
                }
                if (GUILayout.Button("Delete"))
                {
                    if (EditorUtility.DisplayDialog("Deleting Bay Design Entry", "Are you sure you want to delete this bay?", "Delete", "Cancel"))
                    {
                        int deletedBayDesignIndex = bFacade.bayPattern[selectedBayPatternIndex];
                        Debug.Log("Delete Bay Design " + deletedBayDesignIndex);
                        Debug.Log("Delete Bay Design " + data.bays[deletedBayDesignIndex].name);
                        data.bays.RemoveAt(deletedBayDesignIndex);
                        int numberOfFacadeDesigns = data.facades.Count;
                        for (int i = 0; i < numberOfFacadeDesigns; i++)
                        {
                            BuildrFacadeDesign checkFacade = data.facades[i];
                            int bayPatternSize             = checkFacade.bayPattern.Count;
                            for (int j = 0; j < bayPatternSize; j++)
                            {
                                if (checkFacade.bayPattern[j] == deletedBayDesignIndex)
                                {
                                    checkFacade.bayPattern.RemoveAt(j);
                                    j--;
                                    bayPatternSize--;
                                }
                                else if (checkFacade.bayPattern[j] > deletedBayDesignIndex)
                                {
                                    checkFacade.bayPattern[j]--;
                                }
                            }
                        }
                        GUI.changed = true;
                    }
                }
                EditorGUI.BeginDisabledGroup(selectedBayPatternIndex == numberOfBays - 1);
                if (GUILayout.Button(">>", GUILayout.Width(40)))
                {
                    int bayDesignIndex = bFacade.bayPattern[selectedBayPatternIndex];
                    bFacade.bayPattern.Insert(selectedBayPatternIndex + 2, bayDesignIndex);
                    bFacade.bayPattern.RemoveAt(selectedBayPatternIndex);
                    selectedBayPatternIndex++;
                    GUI.changed = true;
                }
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndVertical();

                GUILayout.Space(10);
                EditorGUILayout.BeginVertical("box");
                bBay.name = EditorGUILayout.TextField("Name: ", bBay.name);
                bool bBayisOpening = EditorGUILayout.Toggle("Has Opening", bBay.isOpening);
                if (bBayisOpening != bBay.isOpening)
                {
                    bBay.isOpening = bBayisOpening;
                }

                bool bBayRenderBack = EditorGUILayout.Toggle("Render Back", bBay.renderBack);
                if (bBayRenderBack != bBay.renderBack)
                {
                    bBay.renderBack = bBayRenderBack;
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Bay Model", GUILayout.Width(146));
                bBay.bayModel = (GameObject)EditorGUILayout.ObjectField(bBay.bayModel, typeof(GameObject), false);
                if (GUILayout.Button("Clear", GUILayout.Width(70)))
                {
                    bBay.bayModel = null;
                }
                EditorGUILayout.EndHorizontal();

                float bBayopeningWidth = Mathf.Max(EditorGUILayout.FloatField("Opening Width", bBay.openingWidth), 0);
                if (bBayopeningWidth != bBay.openingWidth)
                {
                    bBay.openingWidth = bBayopeningWidth;
                }
                float bBayopeningHeight = Mathf.Clamp(EditorGUILayout.FloatField("Opening Height", bBay.openingHeight), 0, data.floorHeight);
                if (bBayopeningHeight != bBay.openingHeight)
                {
                    bBay.openingHeight = bBayopeningHeight;
                }

                float bBayminimumBayWidth = Mathf.Max(EditorGUILayout.FloatField("Bay Spacing Width", bBay.minimumBayWidth), 0);
                if (bBayminimumBayWidth != bBay.minimumBayWidth)
                {
                    bBay.minimumBayWidth = bBayminimumBayWidth;
                }

                float bBayopeningWidthRatio = EditorGUILayout.Slider("Horizontal Space Ratio", bBay.openingWidthRatio, 0, 1);
                if (bBayopeningWidthRatio != bBay.openingWidthRatio)
                {
                    bBay.openingWidthRatio = bBayopeningWidthRatio;
                }
                float bBayopeningHeightRatio = EditorGUILayout.Slider("Vertical Space Ratio", bBay.openingHeightRatio, 0, 1);
                if (bBayopeningHeightRatio != bBay.openingHeightRatio)
                {
                    bBay.openingHeightRatio = bBayopeningHeightRatio;
                }

                float bBayopeningDepth = EditorGUILayout.Slider("Opening Depth", bBay.openingDepth, -depth, depth);
                if (bBayopeningDepth != bBay.openingDepth)
                {
                    bBay.openingDepth = bBayopeningDepth;
                }
                float bBaycolumnDepth = EditorGUILayout.Slider("Column depth", bBay.columnDepth, -depth, depth);
                if (bBaycolumnDepth != bBay.columnDepth)
                {
                    bBay.columnDepth = bBaycolumnDepth;
                }
                float bBayrowDepth = EditorGUILayout.Slider("Row depth", bBay.rowDepth, -depth, depth);
                if (bBayrowDepth != bBay.rowDepth)
                {
                    bBay.rowDepth = bBayrowDepth;
                }
                float bBaycrossDepth = EditorGUILayout.Slider("Cross depth", bBay.crossDepth, -depth, depth);
                if (bBaycrossDepth != bBay.crossDepth)
                {
                    bBay.crossDepth = bBaycrossDepth;
                }

                //BAY TEXTURES

                int      numberOfTextureSlots = bBay.numberOfTextures;
                string[] titles = new string[numberOfTextureSlots];
                for (int bft = 0; bft < numberOfTextureSlots; bft++)
                {
                    titles[bft] = ((BuildrBay.TextureNames)(bft)).ToString();
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Surface:", GUILayout.Width(75));
                editTextureOnFacade = EditorGUILayout.Popup(editTextureOnFacade, titles);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Texture:", GUILayout.Width(75));
                bBay.textureValues[editTextureOnFacade] = EditorGUILayout.Popup(bBay.textureValues[editTextureOnFacade], textureNames);
                EditorGUILayout.EndHorizontal();
                BuildrTexture bTexture = data.textures[bBay.textureValues[editTextureOnFacade]];
                Texture2D     texture  = bTexture.texture;
                EditorGUILayout.BeginHorizontal();

                if (texture != null)
                {
                    GUILayout.Label(texture, GUILayout.Width(100), GUILayout.Height(100));
                }
                else
                {
                    EditorGUILayout.HelpBox("No texture assigned for '" + textureNames[bBay.textureValues[editTextureOnFacade]] + "', assign one in the Textures menu above", MessageType.Warning);
                }

                bFacade.flipValues[editTextureOnFacade] = EditorGUILayout.Toggle("Flip 90\u00B0", bFacade.flipValues[editTextureOnFacade]);

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndVertical();
            }
        }
        else
        {
            editTextureOnFacade = 7;
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Surface:", GUILayout.Width(75));
            EditorGUILayout.LabelField("Wall");
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Texture:", GUILayout.Width(75));
            int newFacadeTexture = EditorGUILayout.Popup(bFacade.simpleBay.textureValues[editTextureOnFacade], textureNames);
            if (newFacadeTexture != bFacade.simpleBay.textureValues[editTextureOnFacade])
            {
                bFacade.simpleBay.textureValues[editTextureOnFacade] = newFacadeTexture;
            }
            EditorGUILayout.EndHorizontal();
            BuildrTexture bTexture = data.textures[bFacade.simpleBay.textureValues[editTextureOnFacade]];
            Texture2D     texture  = bTexture.texture;
            EditorGUILayout.BeginHorizontal();

            if (texture != null)
            {
                GUILayout.Label(texture, GUILayout.Width(100), GUILayout.Height(100));
            }
            else
            {
                EditorGUILayout.HelpBox("No texture assigned for '" + textureNames[bFacade.simpleBay.textureValues[editTextureOnFacade]] + "', assign one in the Textures menu above", MessageType.Warning);
            }

            bFacade.simpleBay.flipValues[editTextureOnFacade] = EditorGUILayout.Toggle("Flip 90\u00B0", bFacade.simpleBay.flipValues[editTextureOnFacade]);

            EditorGUILayout.EndHorizontal();
        }
    }
    private static void ImportBays(XmlDocument xml, BuildrData data)
    {
        foreach (XmlNode node in xml.SelectNodes("buildr/bays/bay"))
        {
            BuildrBay bay = new BuildrBay("");
            data.bays.Add(bay);

            bay.name = node["bayName"].FirstChild.Value;
            bay.isOpening = bool.Parse(node["isOpening"].FirstChild.Value);
            bay.openingWidth = float.Parse(node["bayOpeningWidth"].FirstChild.Value);
            bay.openingHeight = float.Parse(node["bayOpeningHeight"].FirstChild.Value);
            bay.minimumBayWidth = float.Parse(node["bayMinimumBayWidth"].FirstChild.Value);
            bay.openingWidthRatio = float.Parse(node["bayOpeningWidthRatio"].FirstChild.Value);
            bay.openingHeightRatio = float.Parse(node["bayOpeningHeightRatio"].FirstChild.Value);
            bay.openingDepth = float.Parse(node["bayOpeningDepth"].FirstChild.Value);
            bay.columnDepth = float.Parse(node["bayColumnDepth"].FirstChild.Value);
            bay.rowDepth = float.Parse(node["bayRowDepth"].FirstChild.Value);
            bay.crossDepth = float.Parse(node["bayCrossDepth"].FirstChild.Value);

            for (int i = 0; i < 8; i++)
            {
                bay.textureValues[i] = int.Parse(node.SelectNodes("bayTextures/texture")[i].FirstChild.Value);
                bay.flipValues[i] = node.SelectNodes("bayflipvalues/flipvalue")[i].FirstChild.Value == valueTrue;
            }
        }
    }
    public static GameObject[] Place(BuildrData data)
    {
        BuildrPlan plan            = data.plan;
        int        numberOfVolumes = plan.numberOfVolumes;

        BuildrTexture[]   textures = data.textures.ToArray();
        List <GameObject> output   = new List <GameObject>();

        float largestDepthValue = 0;//deepest value of a bay design in the building

        foreach (BuildrBay bay in data.bays)
        {
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
        }
        foreach (BuildrFacadeDesign facade in data.facades)
        {
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value
        }
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int          numberOfVolumePoints = volume.points.Count;
            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }

                int     indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
                int     indexA  = f;
                int     indexB  = (f + 1) % numberOfVolumePoints;
                int     indexBP = (f + 2) % numberOfVolumePoints;
                Vector3 p0m     = plan.points[volume.points[indexAM]].vector3;
                Vector3 p0      = plan.points[volume.points[indexA]].vector3;
                Vector3 p1      = plan.points[volume.points[indexB]].vector3;
                Vector3 p1p     = plan.points[volume.points[indexBP]].vector3;

                float   facadeWidth         = Vector3.Distance(p0, p1) - largestDepthValue * 2.0f;
                Vector3 facadeDirection     = (p1 - p0).normalized;
                Vector3 facadeCross         = Vector3.Cross(facadeDirection, Vector3.up).normalized;
                Vector3 lastFacadeDirection = (p0 - p0m).normalized;
                Vector3 nextFacadeDirection = (p1p - p1).normalized;

                //only bother with facade directions when facade may intersect inverted geometry
                float facadeDirDotL   = Vector3.Dot(-facadeDirection, lastFacadeDirection);
                float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
                if (facadeDirDotL <= 0 || facadeCrossDotL <= 0)
                {
                    lastFacadeDirection = -facadeCross;
                }

                float facadeDirDotN   = Vector3.Dot(-facadeDirection, nextFacadeDirection);
                float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
                if (facadeDirDotN <= 0 || facadeCrossDotN <= 0)
                {
                    nextFacadeDirection = facadeCross;
                }


                int floorBase      = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float   floorHeight      = data.floorHeight;
                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                p0 += floorHeightStart;
                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int        floorPatternSize         = 0;
                List <int> facadePatternReference   = new List <int>();  //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int        patternCount             = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                    {
                        facadePatternReference.Add(patternCount);
                    }
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                for (int r = 0; r < rows; r++)
                {
                    //Get the facade style id
                    //need to loop through the facade designs floor by floor until we get to the right one
                    float   currentHeight         = floorHeight * r;
                    Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentHeight;
                    int     modFloor = (r % floorPatternSize);

                    BuildrFacadeDesign facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        if (data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                        {
                            data.illegal = true;
                            return(output.ToArray());
                        }

                        BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                        if (firstBay.openingWidth > facadeWidth)
                        {
                            isBlankWall = true;
                        }
                        if (facadeDesign.bayPattern.Count == 0)
                        {
                            isBlankWall = true;
                        }
                    }
                    else
                    {
                        if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                        {
                            isBlankWall = true;
                        }
                    }

                    if (!isBlankWall)
                    {
                        float patternSize  = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int   numberOfBays = 0;
                        //float actualWindowSpacing;
                        BuildrBay[] bayDesignPattern;
                        int         numberOfBayDesigns;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bayDesignPattern   = new BuildrBay[numberOfBayDesigns];
                            for (int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bayDesignPattern   = new[] { facadeDesign.simpleBay };
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while (true)
                        {
                            int   patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                            if (patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                            {
                                break;
                            }
                            it--;
                            if (it < 0)
                            {
                                break;
                            }
                        }

                        Vector3 windowBase = facadeFloorBaseVector;
                        float   perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                        for (int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;

                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bayDesignPattern[c % numberOfBayStyles];
                            }
                            else
                            {
                                bayStyle = facadeDesign.simpleBay;
                            }

                            GameObject bayModel = bayStyle.bayModel;

                            BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                            Vector2       columnuvunits = columnTexture.tileUnitUV;
                            float         openingWidth  = bayStyle.openingWidth;
                            float         openingHeight = bayStyle.openingHeight;
                            if (columnTexture.patterned)
                            {
                                openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                            }
                            if (bayStyle.openingHeight == floorHeight)
                            {
                                bayStyle.openingHeight = floorHeight;
                            }
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftWidth           = actualWindowSpacing * bayStyle.openingWidthRatio;
                            bool  firstColumn         = c == 0;
                            if (firstColumn)
                            {
                                leftWidth += largestDepthValue;
                            }

                            float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                            if (columnTexture.patterned)
                            {
                                rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;
                            }

                            float   bayWidthSize = openingWidth + actualWindowSpacing;
                            Vector3 bayWidth     = facadeDirection * bayWidthSize;
                            if (!bayStyle.isOpening || bayModel == null)
                            {
                                windowBase += bayWidth;//move base vertor to next bay
                                if (firstColumn)
                                {
                                    windowBase += facadeDirection * (largestDepthValue);
                                }
                                continue;//bay filled - move onto next bay
                            }

                            GameObject     newInstance = (GameObject)Instantiate(bayModel);
                            MeshRenderer[] rends       = newInstance.GetComponentsInChildren <MeshRenderer>();
                            Bounds         modelBounds = rends[0].bounds;
                            foreach (MeshRenderer meshRenderer in rends)
                            {
                                modelBounds.Encapsulate(meshRenderer.bounds);
                            }

                            if (rends.Length == 0)
                            {
                                continue;
                            }

                            Vector3 modelSize = modelBounds.size;
                            Vector3 baySize   = new Vector3(openingWidth, openingHeight, modelSize.z);
                            Vector3 modelScale;
                            modelScale.x = baySize.x / modelSize.x;
                            modelScale.y = baySize.y / modelSize.y;
                            modelScale.z = baySize.z / modelSize.z;
                            newInstance.transform.localScale = modelScale;

                            Vector3 upVector      = Vector3.up * rowBottomHeight;
                            Vector3 leftVector    = leftWidth * facadeDirection;
                            Vector3 modelPosition = windowBase + leftVector + upVector;

                            modelBounds = rends[0].bounds;
                            foreach (MeshRenderer meshRenderer in rends)
                            {
                                modelBounds.Encapsulate(meshRenderer.bounds);
                            }
                            modelPosition += Quaternion.LookRotation(facadeCross) * (-modelBounds.min);
                            newInstance.transform.position = modelPosition;
                            newInstance.transform.rotation = Quaternion.LookRotation(-facadeCross);
                            output.Add(newInstance);

                            windowBase += bayWidth;//move base vertor to next bay
                            if (firstColumn)
                            {
                                windowBase += facadeDirection * (largestDepthValue);
                            }
                        }
                    }
                }
            }
        }
        return(output.ToArray());
    }
    private static void BuildTextures()
    {
        List<TexturePaintObject> buildSourceTextures = new List<TexturePaintObject>();
        foreach (BuildrTexture btexture in data.textures)//Gather the source textures, resized into Color32 arrays
        {
            TexturePaintObject texturePaintObject = new TexturePaintObject();
            texturePaintObject.pixels = ((Texture2D)btexture.texture).GetPixels32();
            texturePaintObject.width = btexture.texture.width;
            texturePaintObject.height = btexture.texture.height;
            texturePaintObject.tiles = new Vector2(btexture.tiledX, btexture.tiledY);
            if (btexture.tiled)
            {
                int resizedTextureWidth = Mathf.RoundToInt(btexture.textureUnitSize.x * PIXELS_PER_METER * packedScale);
                int resizedTextureHeight = Mathf.RoundToInt(btexture.textureUnitSize.y * PIXELS_PER_METER * packedScale);
                texturePaintObject.pixels = TextureScale.NearestNeighbourSample(texturePaintObject.pixels, texturePaintObject.width, texturePaintObject.height, resizedTextureWidth, resizedTextureHeight);
                texturePaintObject.width = resizedTextureWidth;
                texturePaintObject.height = resizedTextureHeight;
            }
            else
            {
                texturePaintObject.tiled = false;
            }
            buildSourceTextures.Add(texturePaintObject);
        }
        TexturePaintObject[] sourceTextures = buildSourceTextures.ToArray();
        textures = data.textures.ToArray();
        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan plan = data.plan;

        int numberOfVolumes = data.plan.numberOfVolumes;
        int facadeNumber = 0;
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;
                int indexA, indexB;
                Vector3 p0, p1;
                indexA = f;
                indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                p0 = plan.points[volume.points[indexA]].vector3;
                p1 = plan.points[volume.points[indexB]].vector3;
                Rect packedPosition = packedTexturePositions[facadeNumber];

                float facadeWidth = Vector3.Distance(p0, p1);
                int floorBase = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int floorPatternSize = 0;
                List<int> facadePatternReference = new List<int>();//this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int patternCount = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits)//need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                        facadePatternReference.Add(patternCount);
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                Vector2 bayBase = Vector2.zero;
                float currentFloorBase = 0;
                for (int r = 0; r < rows; r++)
                {
                    currentFloorBase = floorHeight * r;
                    int modFloor = (r % floorPatternSize);

                    facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                        if (firstBay.openingWidth > facadeWidth) isBlankWall = true;
                        if (facadeDesign.bayPattern.Count == 0) isBlankWall = true;
                    }
                    else
                    {
                        if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                            isBlankWall = true;
                    }
                    if (!isBlankWall)
                    {
                        float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int numberOfBays = 0;
                        BuildrBay[] bays;
                        int numberOfBayDesigns = 0;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bays = new BuildrBay[numberOfBayDesigns];
                            for (int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bays[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bays = new[] { facadeDesign.simpleBay };
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while (true)
                        {
                            int patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bays[patternModIndex].openingWidth + bays[patternModIndex].minimumBayWidth;
                            if (patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                                break;
                            it--;
                            if (it < 0)
                                break;
                        }
                        float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;

                        float windowXBase = 0;
                        for (int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;
                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bays[c % numberOfBayStyles];
                            }
                            else
                            {
                                bayStyle = facadeDesign.simpleBay;
                            }
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftSpace = actualWindowSpacing * bayStyle.openingWidthRatio;
                            float rightSpace = actualWindowSpacing - leftSpace;
                            float openingSpace = bayStyle.openingWidth;

                            Vector3 bayDimensions;
                            int subMesh;
                            bool flipped;

                            if (!bayStyle.isOpening)
                            {
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.WallTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.WallTexture);
                                bayBase.x = windowXBase;
                                bayBase.y = currentFloorBase;
                                float bayWidth = (openingSpace + actualWindowSpacing);
                                float bayHeight = floorHeight;
                                bayDimensions = new Vector2(bayWidth, bayHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                windowXBase += bayWidth;//move base vertor to next bay
                                continue;//bay filled - move onto next bay
                            }

                            float rowBottomHeight = ((floorHeight - bayStyle.openingHeight) * bayStyle.openingHeightRatio);
                            float rowTopHeight = (floorHeight - rowBottomHeight - bayStyle.openingHeight);

                            //Window
                            subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                            flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                            bayBase.x = windowXBase + leftSpace;
                            bayBase.y = currentFloorBase + rowBottomHeight;
                            bayDimensions = new Vector2(bayStyle.openingWidth, bayStyle.openingHeight);
                            DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                            //Column Left
                            if (leftSpace > 0)
                            {
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                                bayBase.x = windowXBase;
                                bayBase.y = currentFloorBase + rowBottomHeight;
                                bayDimensions = new Vector2(leftSpace, bayStyle.openingHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Column Right
                            if (rightSpace > 0)
                            {
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                                bayBase.x = windowXBase + leftSpace + openingSpace;
                                bayBase.y = currentFloorBase + rowBottomHeight;
                                bayDimensions = new Vector2(rightSpace, bayStyle.openingHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Row Bottom
                            if (rowBottomHeight > 0)
                            {
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                                bayBase.x = windowXBase + leftSpace;
                                bayBase.y = currentFloorBase;
                                bayDimensions = new Vector2(openingSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Row Top
                            if (rowTopHeight > 0)
                            {
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                                bayBase.x = windowXBase + leftSpace;
                                bayBase.y = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(openingSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Cross Left
                            if (leftSpace > 0)
                            {
                                //Cross Left Bottom
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x = windowXBase;
                                bayBase.y = currentFloorBase;
                                bayDimensions = new Vector2(leftSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                //Cross Left Top
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x = windowXBase;
                                bayBase.y = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(leftSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Cross Right
                            if (rightSpace > 0)
                            {
                                //Cross Left Bottom
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x = windowXBase + leftSpace + openingSpace;
                                bayBase.y = currentFloorBase;
                                bayDimensions = new Vector2(rightSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                //Cross Left Top
                                subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x = windowXBase + leftSpace + openingSpace;
                                bayBase.y = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(rightSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            windowXBase += leftSpace + openingSpace + rightSpace;//move base vertor to next bay
                        }
                    }
                    else
                    {
                        // windowless wall
                        int subMesh = facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture);
                        bool flipped = facadeDesign.simpleBay.IsFlipped(BuildrBay.TextureNames.WallTexture);
                        bayBase.x = 0;
                        bayBase.y = currentFloorBase;
                        Vector2 dimensions = new Vector2(facadeWidth, floorHeight);
                        DrawFacadeTexture(sourceTextures, bayBase, dimensions, subMesh, flipped, packedPosition);
                    }
                }
                facadeNumber++;
            }
        }

        //add roof textures
        int numberOfroofTextures = roofTextures.Count;
        int scaledPadding = Mathf.FloorToInt(ATLAS_PADDING * packedScale);
        for (int i = 0; i < numberOfroofTextures; i++)
        {
            Rect roofTexturePosition = packedTexturePositions[i + facadeNumber];
            BuildrTexture bTexture = roofTextures[i];
            int roofTextureWidth = bTexture.texture.width;
            int roofTextureHeight = bTexture.texture.height;
            int targetTextureWidth = Mathf.RoundToInt(roofTexturePosition.width);
            int targetTextureHeight = Mathf.RoundToInt(roofTexturePosition.height);
            if (bTexture.maxUVTile == Vector2.zero)
                continue;

            int sourceTextureWidth = Mathf.RoundToInt(targetTextureWidth / (bTexture.tiled ? bTexture.maxUVTile.x : bTexture.tiledX));
            int sourceTextureHeight = Mathf.RoundToInt(targetTextureHeight / (bTexture.tiled ? bTexture.maxUVTile.y : bTexture.tiledY));
            int sourceTextureSize = sourceTextureWidth * sourceTextureHeight;
            if (sourceTextureSize == 0)
            {
                //Debug.Log(sourceTextureWidth+" "+sourceTextureHeight+" "+bTexture.tiledX+" "+bTexture.maxUVTile+" "+bTexture.tiledX+","+bTexture.tiledY);
                continue;
            }
            Color32[] roofColourArray = TextureScale.NearestNeighbourSample(((Texture2D)bTexture.texture).GetPixels32(), roofTextureWidth, roofTextureHeight, sourceTextureWidth, sourceTextureHeight);
            //Color32[] roofColourArray = bTexture.texture.GetPixels32();

            for (int x = 0; x < targetTextureWidth; x++)
            {
                for (int y = 0; y < targetTextureHeight; y++)
                {
                    int drawX = Mathf.FloorToInt(x + roofTexturePosition.x);
                    int drawY = Mathf.FloorToInt(y + roofTexturePosition.y);
                    int colourIndex = drawX + drawY * textureWidth;

                    int sx = x % sourceTextureWidth;
                    int sy = y % sourceTextureHeight;
                    int sourceIndex = sx + sy * sourceTextureWidth;
                    if (sourceIndex >= sourceTextureSize)
                        Debug.Log("Source Index too big " + sx + " " + sy + " " + sourceTextureWidth + " " + sourceTextureSize + " " + bTexture.maxUVTile + " " + bTexture.name);
                    Color32 sourceColour = roofColourArray[sourceIndex];
                    if (colourIndex >= textureSize)
                        Debug.Log("Output Index Too big " + drawX + " " + drawY + " " + colourIndex + " " + textureSize + " " + roofTexturePosition);
                    colourArray[colourIndex] = sourceColour;

                    //Padding
                    if (x == 0)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex - p] = sourceColour;
                        }
                    }
                    if (x == targetTextureWidth - 1)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex + p] = sourceColour;
                        }
                    }

                    if (y == 0)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex - (p * textureWidth)] = sourceColour;
                        }
                    }

                    if (y == targetTextureHeight - 1)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex + (p * textureWidth)] = sourceColour;
                        }
                    }
                }
            }
        }
    }
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex)
    {
        data = _data;
        mesh = _mesh;
        mesh.name = "Interior Mesh Volume " + volumeIndex;
        textures = data.textures.ToArray();

        if(!data.renderInteriors)
            return;

        float largestDepthValue = 0;//deepest value of a bay design in the building
        float tallestBay = 0;
        foreach (BuildrBay bay in data.bays)
        {
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
            tallestBay = Mathf.Max(tallestBay, bay.openingHeight + (data.floorHeight - bay.openingHeight) * bay.openingHeightRatio);
        }
        foreach (BuildrFacadeDesign facade in data.facades)
        {
            if(facade.type != BuildrFacadeDesign.types.simple)
                continue;
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value
            if(facade.simpleBay.isOpening)
                tallestBay = Mathf.Max(tallestBay, facade.simpleBay.openingHeight + (data.floorHeight - facade.simpleBay.openingHeight) * facade.simpleBay.openingHeightRatio);
        }


        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan plan = data.plan;
        BuildrVolume volume = plan.volumes[volumeIndex];
        int numberOfFloors = volume.numberOfFloors;
        float floorHeight = data.floorHeight;
        Vector3 floorHeightVector = Vector3.up * floorHeight;
        float ceilingHeight = tallestBay + (floorHeight - tallestBay) * data.interiorCeilingHeight;

        //Calculate the internal floor plan points
        int numberOfVolumePoints = volume.points.Count;
        Vector2z[] interiorVolumePoints = new Vector2z[numberOfVolumePoints];
        for (int i = 0; i < numberOfVolumePoints; i++)
        {
            Vector3 lastPoint = plan.points[volume.points[(i > 0) ? i - 1 : numberOfVolumePoints - 1]].vector3;
            Vector3 thisPoint = plan.points[volume.points[i]].vector3;
            Vector3 nextPoint = plan.points[volume.points[(i + 1) % numberOfVolumePoints]].vector3;
            Vector3 normalA = Vector3.Cross(thisPoint - lastPoint, Vector3.up).normalized;
            Vector3 normalB = Vector3.Cross(nextPoint - thisPoint, Vector3.up).normalized;

            Vector2z facadeALine = new Vector2z(thisPoint - lastPoint);
            Vector2z facadeBLine = new Vector2z(thisPoint - nextPoint);
            //Calculate facade inner origins for floors
            Vector3 facadeOriginV3A = lastPoint + normalA * largestDepthValue;
            Vector3 facadeOriginV3B = nextPoint + normalB * largestDepthValue;
            Vector2z facadeOriginA = new Vector2z(facadeOriginV3A);
            Vector2z facadeOriginB = new Vector2z(facadeOriginV3B);
            Vector2z facadeLineIntersection = BuildrUtils.FindIntersection(facadeALine, facadeOriginA, facadeBLine, facadeOriginB);

            interiorVolumePoints[i] = facadeLineIntersection;
        }
        List<Vector2z> interiorVolumePointList = new List<Vector2z>(interiorVolumePoints);
        List<Rect> volumeCores = new List<Rect>();
        List<int> linkedPoints = new List<int>();
        foreach (Rect core in plan.cores)
        {
            Vector2z coreCenter = new Vector2z(core.center);
            if (BuildrUtils.PointInsidePoly(coreCenter, interiorVolumePoints))
            {
                volumeCores.Add(core);
            }
        }
        int numberOfVolumeCores = volumeCores.Count;
        bool print = plan.volumes.IndexOf(volume) == 3;
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            int numberOfInteriorPoints = interiorVolumePointList.Count;
            Rect coreBounds = volumeCores[c];
            Vector2z coreCenter = new Vector2z(coreBounds.center);
            Vector2z coreBL = new Vector2z(coreBounds.xMin, coreBounds.yMin);
            Vector2z coreBR = new Vector2z(coreBounds.xMax, coreBounds.yMin);
            Vector2z coreTL = new Vector2z(coreBounds.xMin, coreBounds.yMax);
            Vector2z coreTR = new Vector2z(coreBounds.xMax, coreBounds.yMax);
            Vector2z[] corePointArray;
                corePointArray = new[] { coreBL, coreBR, coreTR, coreTL };
            //Find the nearest legal cut we can make to join the core and interior point poly
            int connectingPoint = -1;
            float connectingPointDistance = Mathf.Infinity;
            for (int p = 0; p < numberOfInteriorPoints; p++)
            {
                if(linkedPoints.Contains(p))
                    continue;
                Vector2z thisPoint = interiorVolumePointList[p];
                float thisPointDistance = Vector2z.SqrMag(thisPoint, coreCenter);
                if (thisPointDistance < connectingPointDistance)
                {
                    bool legalCut = true;
                    for (int pc = 0; pc < numberOfInteriorPoints; pc++)
                    {
                        Vector2z p0 = interiorVolumePointList[pc];
                        Vector2z p1 = interiorVolumePointList[(pc + 1) % numberOfInteriorPoints];
                        if (BuildrUtils.FastLineIntersection(coreCenter, thisPoint, p0, p1))//check against all lines that this new cut doesn't intersect
                        {
                            if (print)
                                Debug.Log("FLI "+pc+" "+coreCenter+" "+thisPoint+" "+p0+" "+p1);
                            legalCut = false;
                            break;
                        }
                    }
                    if (legalCut)
                    {
                        connectingPoint = p;
                        connectingPointDistance = thisPointDistance;
                    }
                }
            }
            if(connectingPoint==-1)
            {
                Debug.Log("Buildr Could not place core");
                continue;
            }
            Vector2z chosenPoint = interiorVolumePointList[connectingPoint];
            int connectingCorePoint = 0;
            float connectingCorePointDistance = Mathf.Infinity;// Vector2z.SqrMag(corePointArray[0], chosenPoint);
            for (int cp = 0; cp < 4; cp++)//find the core point to make the cut
            {
                float thisCorePointDistance = Vector2z.SqrMag(corePointArray[cp], chosenPoint);
                if (thisCorePointDistance < connectingCorePointDistance)
                {
                    connectingCorePoint = cp;
                    connectingCorePointDistance = thisCorePointDistance;
                }
            }
            interiorVolumePointList.Insert(connectingPoint, chosenPoint);//loop back on the floorplan to close it
            for (int acp = 0; acp < 5; acp++)//loop back on itself to close the core
            {
                interiorVolumePointList.Insert(connectingPoint + 1, corePointArray[(connectingCorePoint + acp) % 4]);
            }
            for(int i = 0; i < linkedPoints.Count; i++)
            {
                if (linkedPoints[i] > connectingPoint)
                    linkedPoints[i] += 7;
            }
            linkedPoints.AddRange(new[]{connectingPoint, connectingPoint + 1, connectingPoint + 2, connectingPoint + 3, connectingPoint + 4, connectingPoint + 5, connectingPoint + 6});
//            linkedPoints.AddRange(new []{connectingPoint,connectingPoint+6});
        }
//        if(linkedPoints.Count > 0)
//        Debug.Log(linkedPoints.Count+" "+linkedPoints[0]);
        Vector2z[] interiorPointListCore = interiorVolumePointList.ToArray();

        for (int f = 0; f < numberOfVolumePoints; f++)
        {
            ///WALLS

            int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
            int indexA = f;
            int indexB = (f + 1) % numberOfVolumePoints;
            int indexBP = (f + 2) % numberOfVolumePoints;

            Vector3 p0m = plan.points[volume.points[indexAM]].vector3;
            Vector3 p0 = plan.points[volume.points[indexA]].vector3;
            Vector3 p1 = plan.points[volume.points[indexB]].vector3;
            Vector3 p1p = plan.points[volume.points[indexBP]].vector3;
            Vector3 p0interior = interiorVolumePoints[indexA].vector3;
            Vector3 p1interior = interiorVolumePoints[indexB].vector3;

            float facadeWidth = Vector3.Distance(p0, p1) - largestDepthValue * 2.0f;
            Vector3 facadeDirection = (p1 - p0).normalized;
            Vector3 facadeCross = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 lastFacadeDirection = (p0 - p0m).normalized;
            Vector3 nextFacadeDirection = (p1p - p1).normalized;

            //only bother with facade directions when facade may intersect inverted geometry
            float facadeDirDotL = Vector3.Dot(-facadeDirection, lastFacadeDirection);
            float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
            if (facadeDirDotL <= 0 || facadeCrossDotL <= 0) lastFacadeDirection = -facadeCross;

            float facadeDirDotN = Vector3.Dot(-facadeDirection, nextFacadeDirection);
            float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
            if (facadeDirDotN <= 0 || facadeCrossDotN <= 0) nextFacadeDirection = facadeCross;


            int floorBase = plan.GetFacadeFloorHeight(volumeIndex, volume.points[indexA], volume.points[indexB]);
            BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
            int floorPatternSize = 0;
            List<int> facadePatternReference = new List<int>();//this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
            int patternCount = 0;
            foreach (BuildrVolumeStylesUnit styleUnit in styleUnits)//need to knw how big all the styles are together so we can loop through them
            {
                floorPatternSize += styleUnit.floors;
                for (int i = 0; i < styleUnit.floors; i++)
                    facadePatternReference.Add(patternCount);
                patternCount++;
            }
            facadePatternReference.Reverse();

            int rows = numberOfFloors;


            Vector2 facadeUV = Vector2.zero;

            for (int r = 0; r < rows; r++)
            {
                float currentFloorHeight = floorHeight * r;
                Vector3 currentFloorHeightVector = Vector3.up * (data.floorHeight * r);
                Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentFloorHeight;
                Vector3 ceilingVector = Vector3.up * ceilingHeight;
                if (r < floorBase)
                {
                    //no facade rendered
                    //facade gap filler

                    //interior gap points
                    Vector3 i0 = p1 - facadeDirection.normalized * largestDepthValue;
                    Vector3 i1 = p0 + facadeDirection.normalized * largestDepthValue;

                    Vector3 w0 = i0 + currentFloorHeightVector;
                    Vector3 w1 = i1 + currentFloorHeightVector;
                    Vector3 w2 = w0 + facadeCross * largestDepthValue;
                    Vector3 w3 = w1 + facadeCross * largestDepthValue;
                    Vector3 w4 = w0 + ceilingVector;
                    Vector3 w5 = w1 + ceilingVector;
                    Vector3 w6 = w2 + ceilingVector;
                    Vector3 w7 = w3 + ceilingVector;
                    Vector3 w8 = p1interior + currentFloorHeightVector;
                    Vector3 w9 = p0interior + currentFloorHeightVector;
                    Vector3 w10 = w8 + ceilingVector;
                    Vector3 w11 = w9 + ceilingVector;

                    //floor
                    AddData(new[] { w0, w1, w2, w3 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.FloorTexture(r), false);

                    //ceiling
                    AddData(new[] { w5, w4, w7, w6 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.CeilingTexture(r), false);

                    //sides
                    int wallSubmesh = volume.WallTexture(r);
                    AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));
                    AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));

                    //other gaps
                    float uvWidth1 = Vector3.Distance(w2, w8);
                    AddPlane(w2, w8, w6, w10, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth1, floorHeight));
                    float uvWidth2 = Vector3.Distance(w3, w9);
                    AddPlane(w9, w3, w11, w7, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth2, floorHeight));

                    continue;
                }

                //Get the facade style id
                //need to loop through the facade designs floor by floor until we get to the right one
                int modFloor = ((r - floorBase) % floorPatternSize);

                facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                bool isBlankWall = !facadeDesign.hasWindows;
                if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                {
                    if (data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                    {
                        data.illegal = true;
                        return;
                    }

                    BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                    if (firstBay.openingWidth > facadeWidth) isBlankWall = true;
                    if (facadeDesign.bayPattern.Count == 0) isBlankWall = true;
                }
                else
                {
                    if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                        isBlankWall = true;
                }

                if (!isBlankWall)
                {
                    float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                    int numberOfBays = 0;
                    BuildrBay[] bayDesignPattern;
                    int numberOfBayDesigns;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        numberOfBayDesigns = facadeDesign.bayPattern.Count;
                        bayDesignPattern = new BuildrBay[numberOfBayDesigns];
                        for (int i = 0; i < numberOfBayDesigns; i++)
                        {
                            bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                        }
                    }
                    else
                    {
                        bayDesignPattern = new[] { facadeDesign.simpleBay };
                        numberOfBayDesigns = 1;
                    }
                    //start with first window width - we'll be adding to this until we have filled the facade width
                    int it = 100;
                    while (true)
                    {
                        int patternModIndex = numberOfBays % numberOfBayDesigns;
                        float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                        if (patternSize + patternAddition < facadeWidth)
                        {
                            patternSize += patternAddition;
                            numberOfBays++;
                        }
                        else
                            break;
                        it--;
                        if (it < 0)
                            break;
                    }

                    Vector3 windowBase = facadeFloorBaseVector;
                    facadeUV.x = 0;
                    facadeUV.y += floorHeight;
                    float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                    for (int c = 0; c < numberOfBays; c++)
                    {
                        BuildrBay bayStyle;
                        BuildrBay lastBay;
                        BuildrBay nextBay;
                        bool firstColumn = c == 0;
                        bool lastColumn = c == numberOfBays - 1;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            int numberOfBayStyles = facadeDesign.bayPattern.Count;
                            bayStyle = bayDesignPattern[c % numberOfBayStyles];
                            int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0;
                            lastBay = bayDesignPattern[lastBayIndex];
                            nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles];
                        }
                        else
                        {
                            bayStyle = facadeDesign.simpleBay;
                            lastBay = facadeDesign.simpleBay;
                            nextBay = facadeDesign.simpleBay;
                        }
                        float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                        float leftWidth = actualWindowSpacing * bayStyle.openingWidthRatio;
                        float rightWidth = actualWindowSpacing - leftWidth;
                        float openingWidth = bayStyle.openingWidth;

                        if (firstColumn) leftWidth += largestDepthValue;
                        if (lastColumn) rightWidth += largestDepthValue;

                        BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                        Vector2 columnuvunits = columnTexture.tileUnitUV;
                        float openingHeight = bayStyle.openingHeight;
                        if (columnTexture.patterned) openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                        if (bayStyle.openingHeight == floorHeight) bayStyle.openingHeight = floorHeight;

                        float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                        if (columnTexture.patterned) rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;

                        float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight);

                        bool previousBayIdentical = bayStyle == lastBay;
                        bool nextBayIdentical = bayStyle == nextBay;
                        if (previousBayIdentical && !firstColumn)
                            leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount

                        Vector3 w0, w1, w2, w3;

                        int wallSubmesh = volume.WallTexture(r);
                        bool wallFlipped = false;
                        if (!bayStyle.isOpening)
                        {

                            float bayWidthSize = openingWidth + actualWindowSpacing;
                            if (firstColumn || lastColumn) bayWidthSize += largestDepthValue;
                            Vector3 bayWidth = facadeDirection * bayWidthSize;
                            Vector3 bayHeight = Vector3.up * floorHeight;
                            Vector3 bayDepth = facadeCross * largestDepthValue;
                            w0 = windowBase + bayDepth;
                            w1 = windowBase + bayWidth + bayDepth;
                            w2 = windowBase + bayHeight + bayDepth;
                            w3 = windowBase + bayWidth + bayHeight + bayDepth;
                            Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, facadeUV, bayOpeningUVEnd);

                            windowBase = windowBase + bayWidth;//move base vertor to next bay
                            facadeUV.x += openingWidth + actualWindowSpacing;
                            continue;//bay filled - move onto next bay
                        }

                        var verts = new Vector3[16];
                        verts[0] = windowBase;
                        verts[1] = verts[0] + leftWidth * facadeDirection;
                        verts[2] = verts[1] + openingWidth * facadeDirection;
                        verts[3] = verts[2] + rightWidth * facadeDirection;
                        windowBase = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount
                        facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth;

                        Vector3 rowBottomVector = Vector3.up * rowBottomHeight;
                        verts[4] = verts[0] + rowBottomVector;
                        verts[5] = verts[1] + rowBottomVector;
                        verts[6] = verts[2] + rowBottomVector;
                        verts[7] = verts[3] + rowBottomVector;

                        Vector3 openingVector = Vector3.up * openingHeight;
                        verts[8] = verts[4] + openingVector;
                        verts[9] = verts[5] + openingVector;
                        verts[10] = verts[6] + openingVector;
                        verts[11] = verts[7] + openingVector;

                        Vector3 rowTopVector = Vector3.up * rowTopHeight;
                        verts[12] = verts[8] + rowTopVector;
                        verts[13] = verts[9] + rowTopVector;
                        verts[14] = verts[10] + rowTopVector;
                        verts[15] = verts[11] + rowTopVector;

                        //Realign facade end points
                        if (firstColumn)
                        {
                            verts[0] = p0interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[4] = verts[0] + rowBottomVector;
                            verts[8] = verts[4] + openingVector;
                            verts[12] = verts[8] + rowTopVector;
                        }

                        if (lastColumn)
                        {
                            verts[3] = p1interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[7] = verts[3] + rowBottomVector;
                            verts[11] = verts[7] + openingVector;
                            verts[15] = verts[11] + rowTopVector;
                        }

                        Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth;
                        Vector3 wallDepthVecotr = facadeCross * largestDepthValue;

                        ///WINDOWS
                        int windowSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture); 
                        bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                        w0 = verts[10] + openingDepthVector;
                        w1 = verts[9] + openingDepthVector;
                        w2 = verts[6] + openingDepthVector;
                        w3 = verts[5] + openingDepthVector;
                        Vector2 windowUVStart = new Vector2(0, 0);
                        Vector2 windowUVEnd = new Vector2(openingWidth, openingHeight);
                        if (bayStyle.renderBack && !data.cullBays)
                            AddPlane(w0, w1, w2, w3, windowSubmesh, windowFlipped, windowUVStart, windowUVEnd);

                        ///COLUMNS
                        //Column Face
                        if (leftWidth > 0)//Column Face Left
                        {
                            w0 = verts[4] + wallDepthVecotr;
                            w1 = verts[5] + wallDepthVecotr;
                            w2 = verts[8] + wallDepthVecotr;
                            w3 = verts[9] + wallDepthVecotr;
                            Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight);
                            Vector2 leftColumnUVEnd = leftColumnUVStart + new Vector2(leftWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, leftColumnUVStart, leftColumnUVEnd);
                        }
                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right
                        {
                            w0 = verts[6] + wallDepthVecotr;
                            w1 = verts[7] + wallDepthVecotr;
                            w2 = verts[10] + wallDepthVecotr;
                            w3 = verts[11] + wallDepthVecotr;
                            Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight);
                            Vector2 rightColumnUVEnd = rightColumnUVStart + new Vector2(rightWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, rightColumnUVStart, rightColumnUVEnd);
                        }
                        ///ROWS
                        //Row Bottom
                        if (rowBottomHeight > 0)
                        {
                            w0 = verts[1] + wallDepthVecotr;
                            w1 = verts[2] + wallDepthVecotr;
                            w2 = verts[5] + wallDepthVecotr;
                            w3 = verts[6] + wallDepthVecotr;
                            Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0);
                            Vector2 bottomRowUVEnd = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, bottomRowUVStart, bottomRowUVEnd);
                        }
                        //Row Top
                        if (rowTopHeight > 0)
                        {
                            w0 = verts[9] + wallDepthVecotr;
                            w1 = verts[10] + wallDepthVecotr;
                            w2 = verts[13] + wallDepthVecotr;
                            w3 = verts[14] + wallDepthVecotr;
                            Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight);
                            Vector2 topRowUVEnd = topRowUVStart + new Vector2(openingWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, topRowUVStart, topRowUVEnd);
                        }

                        //Cross Left Bottom
                        w0 = verts[0] + wallDepthVecotr;
                        w1 = verts[1] + wallDepthVecotr;
                        w2 = verts[4] + wallDepthVecotr;
                        w3 = verts[5] + wallDepthVecotr;
                        Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0);
                        Vector2 crossLBUVEnd = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLBUVStart, crossLBUVEnd);

                        //Cross Left Top
                        w0 = verts[8] + wallDepthVecotr;
                        w1 = verts[9] + wallDepthVecotr;
                        w2 = verts[12] + wallDepthVecotr;
                        w3 = verts[13] + wallDepthVecotr;
                        Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight);
                        Vector2 crossLTUVEnd = crossLTUVStart + new Vector2(leftWidth, rowTopHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLTUVStart, crossLTUVEnd);

                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)
                        {
                            //Cross Right Bottom
                            w0 = verts[2] + wallDepthVecotr;
                            w1 = verts[3] + wallDepthVecotr;
                            w2 = verts[6] + wallDepthVecotr;
                            w3 = verts[7] + wallDepthVecotr;
                            Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                            Vector2 crossRBUVEnd = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRBUVStart, crossRBUVEnd);

                            //Cross Right Top
                            w0 = verts[10] + wallDepthVecotr;
                            w1 = verts[11] + wallDepthVecotr;
                            w2 = verts[14] + wallDepthVecotr;
                            w3 = verts[15] + wallDepthVecotr;
                            Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight);
                            Vector2 crossRTUVEnd = crossRTUVStart + new Vector2(rightWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRTUVStart, crossRTUVEnd);
                        }
                    }
                }
                else
                {
                    // windowless wall
                    Vector3 interiorStart = p0interior + currentFloorHeightVector;
                    Vector3 interiorEnd = p1interior + currentFloorHeightVector;
                    //                        Vector3 wallVector = (facadeDirection * facadeWidth);
                    Vector3 wallHeightVector = Vector3.up * floorHeight;
                    Vector3 w0 = interiorStart;
                    Vector3 w1 = interiorEnd;
                    Vector3 w2 = interiorStart + wallHeightVector;
                    Vector3 w3 = interiorEnd + wallHeightVector;
                    BuildrTexture texture = textures[facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture)];
                    var uvSize = new Vector2(facadeWidth * (1.0f / texture.textureUnitSize.x), floorHeight * (1.0f / texture.textureUnitSize.y));
                    Vector2 uvunits = texture.tileUnitUV;
                    uvSize.x = Mathf.Ceil(uvSize.x / uvunits.x) * uvunits.x;
                    uvSize.y = Mathf.Ceil(uvSize.y / uvunits.y) * uvunits.y;
                    int wallSubmesh = 0;
                    bool flipped = false;
                    Vector2 wallUVStart = facadeUV;
                    Vector2 wallUVEnd = facadeUV + new Vector2(facadeWidth, floorHeight);
                    AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd);

                }
            }
        }

        ///FLOORS AND CEILING
        int numberOfBasements = volume.numberOfBasementFloors;
        int numberOfFloorPoints = interiorVolumePoints.Length;
        int[] baseFloorPlanTriangles = EarClipper.Triangulate(interiorVolumePoints);
        int baseFloorVectors = interiorVolumePoints.Length;
        var newEndVerts = new Vector3[baseFloorVectors];
        Vector3 basementBaseDrop = -floorHeightVector * numberOfBasements;
        for (int i = 0; i < baseFloorVectors; i++)
            newEndVerts[i] = interiorVolumePoints[i].vector3 + basementBaseDrop;
        var tris = new List<int>(baseFloorPlanTriangles);

        //Bottom Floor
        int floorSubmesh = volume.FloorTexture(-numberOfBasements);
        AddData(newEndVerts, baseFloorPlanTriangles, floorSubmesh, false);

        //Top Ceiling
        if (true)//Todo: add conditional for roof opening
        {
            Vector3 ceilingHeightVector = floorHeightVector * (numberOfFloors - 1 + numberOfBasements) + Vector3.up * ceilingHeight;
            for (int i = 0; i < baseFloorVectors; i++)
                newEndVerts[i] += ceilingHeightVector;
            tris.Reverse(); 
            AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(numberOfFloors-1), false);
        }

        //inner floors
        int[] floorPlanTriangles = EarClipper.Triangulate(interiorPointListCore);
        int numberOfFloorVectors = interiorPointListCore.Length;
        for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors; floorIndex++)
        {
            Vector3 floorVectorHeight = floorHeightVector * floorIndex;
            newEndVerts = new Vector3[numberOfFloorVectors];
            for (int i = 0; i < numberOfFloorVectors; i++)
            {
                newEndVerts[i] = interiorPointListCore[i].vector3 + floorVectorHeight;
            }
            tris = new List<int>(floorPlanTriangles);

            //Floor
            if (floorIndex > -numberOfBasements)
                AddData(newEndVerts, tris.ToArray(), volume.FloorTexture(floorIndex), false);

            //Ceiling
            if (floorIndex < numberOfFloors - 1)
            {
                Vector3 ceilingHeightVector = Vector3.up * ceilingHeight;
                for (int i = 0; i < numberOfFloorVectors; i++)
                {
                    newEndVerts[i] += ceilingHeightVector;
                }
                tris.Reverse();
                AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(floorIndex), false);
            }

            //basement walls
            if(floorIndex < 0)
            {
                for (int f = 0; f < numberOfFloorPoints; f++)
                {
                    Vector3 basementVector = floorHeightVector * floorIndex;
                    int indexA = f;
                    int indexB = (f + 1) % numberOfFloorPoints;

                    Vector3 p0 = interiorVolumePoints[indexA].vector3 + basementVector;
                    Vector3 p1 = interiorVolumePoints[indexB].vector3 + basementVector;
                    Vector3 p2 = p0 + floorHeightVector;
                    Vector3 p3 = p1 + floorHeightVector;
                    Vector2 uv1 = new Vector2(Vector3.Distance(p0,p1), floorHeight);
                    AddPlane(p0, p1, p2, p3, volume.WallTexture(floorIndex), false, Vector2.zero, uv1);
                }
            }
        }

        //Core walls
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            Rect coreBounds = volumeCores[c];
            Vector3 coreBL = new Vector3(coreBounds.xMin, 0, coreBounds.yMin);
            Vector3 coreBR = new Vector3(coreBounds.xMax, 0, coreBounds.yMin);
            Vector3 coreTL = new Vector3(coreBounds.xMin, 0, coreBounds.yMax);
            Vector3 coreTR = new Vector3(coreBounds.xMax, 0, coreBounds.yMax);

            for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors - 1; floorIndex++)
            {
                Vector3 c0 = floorHeightVector * floorIndex + Vector3.up * ceilingHeight;
                Vector3 f0 = floorHeightVector * floorIndex + Vector3.up * floorHeight;
                float gapHeight = floorHeight - ceilingHeight;
                AddPlane(coreBL + c0, coreBR + c0, coreBL + f0, coreBR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreBR + c0, coreTR + c0, coreBR + f0, coreTR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTR + c0, coreTL + c0, coreTR + f0, coreTL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTL + c0, coreBL + c0, coreTL + f0, coreBL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
            }
        }
    }
Exemple #16
0
    private static void BuildTextures()
    {
        List <TexturePaintObject> buildSourceTextures = new List <TexturePaintObject>();

        foreach (BuildrTexture btexture in data.textures)//Gather the source textures, resized into Color32 arrays
        {
            TexturePaintObject texturePaintObject = new TexturePaintObject();
            texturePaintObject.pixels = ((Texture2D)btexture.texture).GetPixels32();
            texturePaintObject.width  = btexture.texture.width;
            texturePaintObject.height = btexture.texture.height;
            texturePaintObject.tiles  = new Vector2(btexture.tiledX, btexture.tiledY);
            if (btexture.tiled)
            {
                int resizedTextureWidth  = Mathf.RoundToInt(btexture.textureUnitSize.x * PIXELS_PER_METER * packedScale);
                int resizedTextureHeight = Mathf.RoundToInt(btexture.textureUnitSize.y * PIXELS_PER_METER * packedScale);
                texturePaintObject.pixels = TextureScale.NearestNeighbourSample(texturePaintObject.pixels, texturePaintObject.width, texturePaintObject.height, resizedTextureWidth, resizedTextureHeight);
                texturePaintObject.width  = resizedTextureWidth;
                texturePaintObject.height = resizedTextureHeight;
            }
            else
            {
                texturePaintObject.tiled = false;
            }
            buildSourceTextures.Add(texturePaintObject);
        }
        LogTimer("Gather Source into Arrays");
        TexturePaintObject[] sourceTextures = buildSourceTextures.ToArray();
        textures = data.textures.ToArray();
        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan         plan         = data.plan;

        int numberOfVolumes = data.plan.numberOfVolumes;
        int facadeNumber    = 0;

        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int     indexA, indexB;
                Vector3 p0, p1;
                indexA = f;
                indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                p0     = plan.points[volume.points[indexA]].vector3;
                p1     = plan.points[volume.points[indexB]].vector3;
                Rect packedPosition = packedTexturePositions[facadeNumber];

                float facadeWidth    = Vector3.Distance(p0, p1);
                int   floorBase      = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int   numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int        floorPatternSize         = 0;
                List <int> facadePatternReference   = new List <int>();  //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int        patternCount             = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                    {
                        facadePatternReference.Add(patternCount);
                    }
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                Vector2 bayBase          = Vector2.zero;
                float   currentFloorBase = 0;
                for (int r = 0; r < rows; r++)
                {
                    currentFloorBase = floorHeight * r;
                    int modFloor = (r % floorPatternSize);

                    facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                        if (firstBay.openingWidth > facadeWidth)
                        {
                            isBlankWall = true;
                        }
                        if (facadeDesign.bayPattern.Count == 0)
                        {
                            isBlankWall = true;
                        }
                    }
                    else
                    {
                        if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                        {
                            isBlankWall = true;
                        }
                    }
                    if (!isBlankWall)
                    {
                        float       patternSize  = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int         numberOfBays = 0;
                        BuildrBay[] bays;
                        int         numberOfBayDesigns = 0;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bays = new BuildrBay[numberOfBayDesigns];
                            for (int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bays[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bays = new[] { facadeDesign.simpleBay };
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while (true)
                        {
                            int   patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bays[patternModIndex].openingWidth + bays[patternModIndex].minimumBayWidth;
                            if (patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                            {
                                break;
                            }
                            it--;
                            if (it < 0)
                            {
                                break;
                            }
                        }
                        float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;

                        float windowXBase = 0;
                        for (int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;
                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bays[c % numberOfBayStyles];
                            }
                            else
                            {
                                bayStyle = facadeDesign.simpleBay;
                            }
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftSpace           = actualWindowSpacing * bayStyle.openingWidthRatio;
                            float rightSpace          = actualWindowSpacing - leftSpace;
                            float openingSpace        = bayStyle.openingWidth;

                            Vector3 bayDimensions;
                            int     subMesh;
                            bool    flipped;

                            if (!bayStyle.isOpening)
                            {
                                subMesh   = bayStyle.GetTexture(BuildrBay.TextureNames.WallTexture);
                                flipped   = bayStyle.IsFlipped(BuildrBay.TextureNames.WallTexture);
                                bayBase.x = windowXBase;
                                bayBase.y = currentFloorBase;
                                float bayWidth  = (openingSpace + actualWindowSpacing);
                                float bayHeight = floorHeight;
                                bayDimensions = new Vector2(bayWidth, bayHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                windowXBase += bayWidth; //move base vertor to next bay
                                continue;                //bay filled - move onto next bay
                            }

                            float rowBottomHeight = ((floorHeight - bayStyle.openingHeight) * bayStyle.openingHeightRatio);
                            float rowTopHeight    = (floorHeight - rowBottomHeight - bayStyle.openingHeight);

                            //Window
                            subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                            flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                            bayBase.x     = windowXBase + leftSpace;
                            bayBase.y     = currentFloorBase + rowBottomHeight;
                            bayDimensions = new Vector2(bayStyle.openingWidth, bayStyle.openingHeight);
                            DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                            //Column Left
                            if (leftSpace > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                                bayBase.x     = windowXBase;
                                bayBase.y     = currentFloorBase + rowBottomHeight;
                                bayDimensions = new Vector2(leftSpace, bayStyle.openingHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Column Right
                            if (rightSpace > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                                bayBase.x     = windowXBase + leftSpace + openingSpace;
                                bayBase.y     = currentFloorBase + rowBottomHeight;
                                bayDimensions = new Vector2(rightSpace, bayStyle.openingHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Row Bottom
                            if (rowBottomHeight > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                                bayBase.x     = windowXBase + leftSpace;
                                bayBase.y     = currentFloorBase;
                                bayDimensions = new Vector2(openingSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Row Top
                            if (rowTopHeight > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                                bayBase.x     = windowXBase + leftSpace;
                                bayBase.y     = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(openingSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Cross Left
                            if (leftSpace > 0)
                            {
                                //Cross Left Bottom
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase;
                                bayBase.y     = currentFloorBase;
                                bayDimensions = new Vector2(leftSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                //Cross Left Top
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase;
                                bayBase.y     = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(leftSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Cross Right
                            if (rightSpace > 0)
                            {
                                //Cross Left Bottom
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase + leftSpace + openingSpace;
                                bayBase.y     = currentFloorBase;
                                bayDimensions = new Vector2(rightSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                //Cross Left Top
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase + leftSpace + openingSpace;
                                bayBase.y     = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(rightSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            windowXBase += leftSpace + openingSpace + rightSpace;//move base vertor to next bay
                        }
                    }
                    else
                    {
                        // windowless wall
                        int  subMesh = facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture);
                        bool flipped = facadeDesign.simpleBay.IsFlipped(BuildrBay.TextureNames.WallTexture);
                        bayBase.x = 0;
                        bayBase.y = currentFloorBase;
                        Vector2 dimensions = new Vector2(facadeWidth, floorHeight);
                        DrawFacadeTexture(sourceTextures, bayBase, dimensions, subMesh, flipped, packedPosition);
                    }
                }
                facadeNumber++;
            }
        }
        LogTimer("generate facade textures");

        //add roof textures
        int numberOfroofTextures = roofTextures.Count;
        int scaledPadding        = Mathf.FloorToInt(ATLAS_PADDING * packedScale);

        for (int i = 0; i < numberOfroofTextures; i++)
        {
            Rect          roofTexturePosition = packedTexturePositions[i + facadeNumber];
            BuildrTexture bTexture            = roofTextures[i];
            int           roofTextureWidth    = bTexture.texture.width;
            int           roofTextureHeight   = bTexture.texture.height;
            int           targetTextureWidth  = Mathf.RoundToInt(roofTexturePosition.width);
            int           targetTextureHeight = Mathf.RoundToInt(roofTexturePosition.height);
            if (bTexture.maxUVTile == Vector2.zero)
            {
                LogTimer("BuildTextures: Skip texture " + bTexture.name + " as it appears it's not used");
                continue;
            }
            int sourceTextureWidth  = Mathf.RoundToInt(targetTextureWidth / (bTexture.tiled ? bTexture.maxUVTile.x : bTexture.tiledX));
            int sourceTextureHeight = Mathf.RoundToInt(targetTextureHeight / (bTexture.tiled ? bTexture.maxUVTile.y : bTexture.tiledY));
            int sourceTextureSize   = sourceTextureWidth * sourceTextureHeight;
            if (sourceTextureSize == 0)
            {
                //Debug.Log(sourceTextureWidth+" "+sourceTextureHeight+" "+bTexture.tiledX+" "+bTexture.maxUVTile+" "+bTexture.tiledX+","+bTexture.tiledY);
                continue;
            }
            Color32[] roofColourArray = TextureScale.NearestNeighbourSample(((Texture2D)bTexture.texture).GetPixels32(), roofTextureWidth, roofTextureHeight, sourceTextureWidth, sourceTextureHeight);
            //Color32[] roofColourArray = bTexture.texture.GetPixels32();

            for (int x = 0; x < targetTextureWidth; x++)
            {
                for (int y = 0; y < targetTextureHeight; y++)
                {
                    int drawX       = Mathf.FloorToInt(x + roofTexturePosition.x);
                    int drawY       = Mathf.FloorToInt(y + roofTexturePosition.y);
                    int colourIndex = drawX + drawY * textureWidth;

                    int sx          = x % sourceTextureWidth;
                    int sy          = y % sourceTextureHeight;
                    int sourceIndex = sx + sy * sourceTextureWidth;
                    if (sourceIndex >= sourceTextureSize)
                    {
                        Debug.Log("Source Index too big " + sx + " " + sy + " " + sourceTextureWidth + " " + sourceTextureSize + " " + bTexture.maxUVTile + " " + bTexture.name);
                    }
                    Color32 sourceColour = roofColourArray[sourceIndex];
                    if (colourIndex >= textureSize)
                    {
                        Debug.Log("Output Index Too big " + drawX + " " + drawY + " " + colourIndex + " " + textureSize + " " + roofTexturePosition);
                    }
                    colourArray[colourIndex] = sourceColour;

                    //Padding
                    if (x == 0)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex - p] = sourceColour;
                        }
                    }
                    if (x == targetTextureWidth - 1)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex + p] = sourceColour;
                        }
                    }

                    if (y == 0)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex - (p * textureWidth)] = sourceColour;
                        }
                    }

                    if (y == targetTextureHeight - 1)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex + (p * textureWidth)] = sourceColour;
                        }
                    }
                }
            }
        }
        LogTimer("generate roof textures");
    }
    public static GameObject[] Place(BuildrData data)
    {
        BuildrPlan plan = data.plan;
        int numberOfVolumes = plan.numberOfVolumes;
        BuildrTexture[] textures = data.textures.ToArray();
        List<GameObject> output = new List<GameObject>();

        float largestDepthValue = 0;//deepest value of a bay design in the building
        foreach (BuildrBay bay in data.bays)
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
        foreach (BuildrFacadeDesign facade in data.facades)
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value

        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int numberOfVolumePoints = volume.points.Count;
            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;

                int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
                int indexA = f;
                int indexB = (f + 1) % numberOfVolumePoints;
                int indexBP = (f + 2) % numberOfVolumePoints;
                Vector3 p0m = plan.points[volume.points[indexAM]].vector3;
                Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                Vector3 p1 = plan.points[volume.points[indexB]].vector3;
                Vector3 p1p = plan.points[volume.points[indexBP]].vector3;

                float facadeWidth = Vector3.Distance(p0, p1) - largestDepthValue*2.0f;
                Vector3 facadeDirection = (p1 - p0).normalized;
                Vector3 facadeCross = Vector3.Cross(facadeDirection, Vector3.up).normalized;
                Vector3 lastFacadeDirection = (p0 - p0m).normalized;
                Vector3 nextFacadeDirection = (p1p - p1).normalized;

                //only bother with facade directions when facade may intersect inverted geometry
                float facadeDirDotL = Vector3.Dot(-facadeDirection, lastFacadeDirection);
                float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
                if (facadeDirDotL <= 0 || facadeCrossDotL <= 0) lastFacadeDirection = -facadeCross;

                float facadeDirDotN = Vector3.Dot(-facadeDirection, nextFacadeDirection);
                float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
                if (facadeDirDotN <= 0 || facadeCrossDotN <= 0) nextFacadeDirection = facadeCross;

                int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;
                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                p0 += floorHeightStart;
                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int floorPatternSize = 0;
                List<int> facadePatternReference = new List<int>();//this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int patternCount = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits)//need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                        facadePatternReference.Add(patternCount);
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                for(int r = 0; r < rows; r++)
                {
                    //Get the facade style id
                    //need to loop through the facade designs floor by floor until we get to the right one
                    float currentHeight = floorHeight * r;
                    Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentHeight;
                    int modFloor = (r % floorPatternSize);

                    BuildrFacadeDesign facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if(facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        if(data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                        {
                            data.illegal = true;
                            return output.ToArray();
                        }

                        BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                        if(firstBay.openingWidth > facadeWidth) isBlankWall = true;
                        if(facadeDesign.bayPattern.Count == 0) isBlankWall = true;
                    }
                    else
                    {
                        if(facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                            isBlankWall = true;
                    }

                    if(!isBlankWall)
                    {
                        float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int numberOfBays = 0;
                        //float actualWindowSpacing;
                        BuildrBay[] bayDesignPattern;
                        int numberOfBayDesigns;
                        if(facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bayDesignPattern = new BuildrBay[numberOfBayDesigns];
                            for(int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bayDesignPattern = new[]{facadeDesign.simpleBay};
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while(true)
                        {
                            int patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                            if(patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                                break;
                            it--;
                            if(it < 0)
                                break;
                        }

                        Vector3 windowBase = facadeFloorBaseVector;
                        float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                        for(int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;

                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bayDesignPattern[c % numberOfBayStyles];
                            }
                            else
                                bayStyle = facadeDesign.simpleBay;

                            GameObject bayModel = bayStyle.bayModel;

                            BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                            Vector2 columnuvunits = columnTexture.tileUnitUV;
                            float openingWidth = bayStyle.openingWidth;
                            float openingHeight = bayStyle.openingHeight;
                            if (columnTexture.patterned) openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                            if (bayStyle.openingHeight == floorHeight) bayStyle.openingHeight = floorHeight;
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftWidth = actualWindowSpacing * bayStyle.openingWidthRatio;
                            bool firstColumn = c == 0;
                            if (firstColumn) leftWidth += largestDepthValue;

                            float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                            if (columnTexture.patterned) rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;

                            float bayWidthSize = openingWidth + actualWindowSpacing;
                            Vector3 bayWidth = facadeDirection * bayWidthSize;
                            if (!bayStyle.isOpening || bayModel == null)
                            {
                                windowBase += bayWidth;//move base vertor to next bay
                                if (firstColumn) windowBase += facadeDirection * (largestDepthValue);
                                continue;//bay filled - move onto next bay
                            }

                            GameObject newInstance = (GameObject)Instantiate(bayModel);
                            MeshRenderer[] rends = newInstance.GetComponentsInChildren<MeshRenderer>();
                            Bounds modelBounds = rends[0].bounds;
                            foreach(MeshRenderer meshRenderer in rends)
                                modelBounds.Encapsulate(meshRenderer.bounds);

                            if(rends.Length == 0)
                                continue;

                            Vector3 modelSize = modelBounds.size;
                            Vector3 baySize = new Vector3(openingWidth, openingHeight, modelSize.z);
                            Vector3 modelScale;
                            modelScale.x = baySize.x / modelSize.x;
                            modelScale.y = baySize.y / modelSize.y;
                            modelScale.z = baySize.z / modelSize.z;
                            newInstance.transform.localScale = modelScale;

                            Vector3 upVector = Vector3.up * rowBottomHeight;
                            Vector3 leftVector = leftWidth * facadeDirection;
                            Vector3 modelPosition = windowBase + leftVector + upVector;

                            modelBounds = rends[0].bounds;
                            foreach (MeshRenderer meshRenderer in rends)
                                modelBounds.Encapsulate(meshRenderer.bounds);
                            modelPosition += Quaternion.LookRotation(facadeCross) * (-modelBounds.min);
                            newInstance.transform.position = modelPosition;
                            newInstance.transform.rotation = Quaternion.LookRotation(-facadeCross);
                            output.Add(newInstance);

                            windowBase += bayWidth;//move base vertor to next bay
                            if (firstColumn) windowBase += facadeDirection * (largestDepthValue);
                        }
                    }
                }
            }
        }
        return output.ToArray();
    }