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 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]--; } } } }
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; }
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); }
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)); } } }
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(); } }
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)); } } }
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(); }