private static void AddData(Vector3[] verts, int[] tris, int subMesh, bool flipped) { int textureSubmesh = subMesh; BuildrTexture texture = textures[textureSubmesh]; Vector2 uvScale = Vector2.one; if (texture.tiled) { uvScale.x = (1.0f / texture.textureUnitSize.x); uvScale.y = (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvScale.x = Mathf.Max(Mathf.Floor(uvScale.x / uvunits.x), 0) * uvunits.x; uvScale.y = Mathf.Max(Mathf.Floor(uvScale.y / uvunits.y), 0) * uvunits.y; } } int numberOfVerts = verts.Length; Vector2[] uvs = new Vector2[numberOfVerts]; for (int i = 0; i < numberOfVerts; i++) { uvs[i] = new Vector2(verts[i].x * uvScale.x, verts[i].z * uvScale.y); if (flipped) { Vector2 flippedUV = new Vector2(uvs[i].y, uvs[i].x); uvs[i] = flippedUV; } } mesh.AddData(verts, uvs, tris, textureSubmesh); }
private static void AddPlane(BuildrRoofDesign design, Vector3 w0, Vector3 w1, Vector3 w2, Vector3 w3, int subMesh, bool flipped) { int textureSubmesh = subMesh; BuildrTexture texture = textures[textureSubmesh]; Vector2 uvSize = Vector2.one; if (texture.tiled) { float planeWidth = Vector3.Distance(w0, w1); float planeHeight = Vector3.Distance(w0, w2); uvSize = new Vector2(planeWidth * (1.0f / texture.textureUnitSize.x), planeHeight * (1.0f / texture.textureUnitSize.y)); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvSize.x = Mathf.Ceil(uvSize.x / uvunits.x) * uvunits.x; uvSize.y = Mathf.Ceil(uvSize.y / uvunits.y) * uvunits.y; } } else { uvSize.x = texture.tiledX; uvSize.y = texture.tiledY; } if (!flipped) { mesh.AddPlane(w0, w1, w2, w3, Vector2.zero, uvSize, textureSubmesh); } else { uvSize = new Vector2(uvSize.y, uvSize.x); mesh.AddPlane(w0, w1, w2, w3, Vector2.zero, uvSize, textureSubmesh); } }
private void CheckData() { XmlNodeList xmlTextures = null; if (File.Exists(textureFilePath)) { XmlDocument xml = new XmlDocument(); StreamReader sr = new StreamReader(textureFilePath); xml.LoadXml(sr.ReadToEnd()); sr.Close(); xmlTextures = xml.SelectNodes("data/textures/texture"); } if (xmlTextures != null) { textures.Clear(); foreach (XmlNode node in xmlTextures) { string filepath = node["filepath"].FirstChild.Value; string[] splits = filepath.Split(filenameDelimiters); BuildrTexture bTexture = new BuildrTexture(splits[splits.Length - 1]); Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(filepath, typeof(Texture2D)); bTexture.texture = texture; bTexture.tiled = node["tiled"].FirstChild.Value == "True"; bTexture.patterned = node["patterned"].FirstChild.Value == "True"; Vector2 tileUnitUV; tileUnitUV.x = float.Parse(node["tileUnitUVX"].FirstChild.Value); tileUnitUV.y = float.Parse(node["tileUnitUVY"].FirstChild.Value); bTexture.tileUnitUV = tileUnitUV; Vector2 textureUnitSize; textureUnitSize.x = float.Parse(node["textureUnitSizeX"].FirstChild.Value); textureUnitSize.y = float.Parse(node["textureUnitSizeY"].FirstChild.Value); bTexture.textureUnitSize = textureUnitSize; bTexture.tiledX = int.Parse(node["tiledX"].FirstChild.Value); bTexture.tiledY = int.Parse(node["tiledY"].FirstChild.Value); bTexture.door = node["door"].FirstChild.Value == "True"; bTexture.window = node["window"].FirstChild.Value == "True"; bTexture.wall = node["wall"].FirstChild.Value == "True"; bTexture.roof = node["roof"].FirstChild.Value == "True"; textures.Add(bTexture); } } /*else * { * GenerateData(); * }*/ }
private void CheckData() { XmlNodeList xmlTextures = null; if (File.Exists(textureFilePath)) { XmlDocument xml = new XmlDocument(); StreamReader sr = new StreamReader(textureFilePath); xml.LoadXml(sr.ReadToEnd()); sr.Close(); xmlTextures = xml.SelectNodes("data/textures/texture"); } if (xmlTextures != null) { textures.Clear(); foreach (XmlNode node in xmlTextures) { string filepath = node["filepath"].FirstChild.Value; string[] splits = filepath.Split(filenameDelimiters); BuildrTexture bTexture = new BuildrTexture(splits[splits.Length - 1]); Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(filepath, typeof(Texture2D)); bTexture.texture = texture; bTexture.tiled = node["tiled"].FirstChild.Value == "True"; bTexture.patterned = node["patterned"].FirstChild.Value == "True"; Vector2 tileUnitUV; tileUnitUV.x = float.Parse(node["tileUnitUVX"].FirstChild.Value); tileUnitUV.y = float.Parse(node["tileUnitUVY"].FirstChild.Value); bTexture.tileUnitUV = tileUnitUV; Vector2 textureUnitSize; textureUnitSize.x = float.Parse(node["textureUnitSizeX"].FirstChild.Value); textureUnitSize.y = float.Parse(node["textureUnitSizeY"].FirstChild.Value); bTexture.textureUnitSize = textureUnitSize; bTexture.tiledX = int.Parse(node["tiledX"].FirstChild.Value); bTexture.tiledY = int.Parse(node["tiledY"].FirstChild.Value); bTexture.door = node["door"].FirstChild.Value == "True"; bTexture.window = node["window"].FirstChild.Value == "True"; bTexture.wall = node["wall"].FirstChild.Value == "True"; bTexture.roof = node["roof"].FirstChild.Value == "True"; textures.Add(bTexture); } } /*else { GenerateData(); }*/ }
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]--; } } } }
private static void ImportTextures(XmlDocument xml, BuildrData data) { foreach (XmlNode node in xml.SelectNodes("buildr/textures/texture")) { BuildrTexture texture = new BuildrTexture(""); data.textures.Add(texture); texture.name = node["name"].FirstChild.Value; texture.tiled = node["tiled"].FirstChild.Value == valueTrue; texture.patterned = node["patterned"].FirstChild.Value == valueTrue; texture.texture = (Texture2D)AssetDatabase.LoadAssetAtPath(node["texture"].FirstChild.Value, typeof(Texture2D)); texture.tileUnitUV = new Vector2(float.Parse(node["tileUnitUV"]["x"].FirstChild.Value), float.Parse(node["tileUnitUV"]["y"].FirstChild.Value)); texture.textureUnitSize = new Vector2(float.Parse(node["textureUnitSize"]["x"].FirstChild.Value), float.Parse(node["textureUnitSize"]["y"].FirstChild.Value)); } }
private static void Steeple(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; int numberOfVolumePoints = volume.points.Count; Vector3[] basePoints = new Vector3[numberOfVolumePoints]; Vector3 centrePoint = Vector3.zero; for (int l = 0; l < numberOfVolumePoints; l++) { basePoints[l] = area.points[volume.points[l]].vector3 + volumeFloorHeight; centrePoint += area.points[volume.points[l]].vector3; } centrePoint = (centrePoint / numberOfVolumePoints) + volumeFloorHeight + ridgeVector; for (int l = 0; l < numberOfVolumePoints; l++) { int pointIndexA = l; int pointIndexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0; Vector3[] verts = new Vector3[3] { basePoints[pointIndexA], basePoints[pointIndexB], centrePoint }; float uvWdith = Vector3.Distance(basePoints[pointIndexA], basePoints[pointIndexB]); float uvHeight = design.height; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdith *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdith = Mathf.Ceil(uvWdith / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdith = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvs = new Vector2[3] { new Vector2(-uvWdith / 2, 0), new Vector2(uvWdith / 2, 0), new Vector2(0, uvHeight) }; int[] tri = new int[3] { 1, 0, 2 }; AddData(verts, uvs, tri, subMesh); } }
private static void GetTextures(BuildrData data) { //Load in textures from the RESOURCES folder wallTexture = new BuildrTexture("wall");//wall wallTexture.texture = (Texture2D)Resources.Load("Textures/BrickSmallBrown0078_2_S"); data.textures.Add(wallTexture); windowTexture = new BuildrTexture("window");//window windowTexture.texture = (Texture2D)Resources.Load("Textures/WindowsHouseOld0260_S"); data.textures.Add(windowTexture); roofTexture = new BuildrTexture("roof");//roof roofTexture.texture = (Texture2D)Resources.Load("Textures/RooftilesMetal0012_2_S"); data.textures.Add(roofTexture); doorTexture = new BuildrTexture("door");//door doorTexture.texture = (Texture2D)Resources.Load("Textures/DoorsWoodPanelled0124_S"); data.textures.Add(doorTexture); }
private void GenerateData() { string[] paths = Directory.GetFiles("Assets/Buildr/Textures"); textures.Clear(); foreach (string path in paths) { if (path.Contains(".meta")) { continue; } Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)); if (texture != null) { string[] splits = path.Split(filenameDelimiters); BuildrTexture bTexture = new BuildrTexture(splits[splits.Length - 1]); bTexture.texture = texture; textures.Add(bTexture); } } }
public void UpdateTextures() { int numberOfMeshes = fullMesh.meshCount; int numberOfMaterials = data.textures.Count; List <Material> buildMaterials = new List <Material>(numberOfMaterials); for (int i = 0; i < numberOfMeshes; i++) { buildMaterials.Clear(); for (int m = 0; m < numberOfMaterials; m++) { if (!fullMesh[i].SubmeshUsed(m)) { continue;//skip, unused } BuildrTexture bTexture = data.textures[m]; buildMaterials.Add(bTexture.usedMaterial); } meshHolders[i].GetComponent <MeshRenderer>().sharedMaterials = buildMaterials.ToArray(); } }
public BuildrTexture Duplicate(string newName) { BuildrTexture newTexture = new BuildrTexture(newName); newTexture.tiled = true; newTexture.patterned = false; newTexture.tileUnitUV = _tileUnitUV; newTexture.textureUnitSize = _textureUnitSize; newTexture.tiledX = tiledX; newTexture.tiledY = tiledY; newTexture.maxUVTile = maxUVTile; newTexture.material = new Material(material); newTexture.tiledTexture = tiledTexture; newTexture.door = door; newTexture.window = window; newTexture.wall = wall; newTexture.roof = roof; newTexture.proceduralMaterial = _proceduralMaterial; newTexture.userMaterial = _userMaterial; return(newTexture); }
private static void AddPlane(Vector3 w0, Vector3 w1, Vector3 w2, Vector3 w3, int subMesh, bool flipped, Vector2 facadeUVStart, Vector2 facadeUVEnd) { int textureSubmesh = subMesh; BuildrTexture texture = textures[textureSubmesh]; Vector2 uvStart = facadeUVStart; Vector2 uvEnd = facadeUVEnd; if (texture.tiled) { uvStart = new Vector2(facadeUVStart.x * (1.0f / texture.textureUnitSize.x), facadeUVStart.y * (1.0f / texture.textureUnitSize.y)); uvEnd = new Vector2(facadeUVEnd.x * (1.0f / texture.textureUnitSize.x), facadeUVEnd.y * (1.0f / texture.textureUnitSize.y)); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvStart.x = Mathf.Max(Mathf.Floor(uvStart.x / uvunits.x), 0) * uvunits.x; uvStart.y = Mathf.Max(Mathf.Floor(uvStart.y / uvunits.y), 0) * uvunits.y; uvEnd.x = Mathf.Max(Mathf.Ceil(uvEnd.x / uvunits.x), 1) * uvunits.x; uvEnd.y = Mathf.Max(Mathf.Ceil(uvEnd.y / uvunits.y), 1) * uvunits.y; } } else { uvStart = Vector2.zero; uvEnd.x = texture.tiledX; uvEnd.y = texture.tiledY; } if (!flipped) { mesh.AddPlane(w2, w3, w0, w1, uvStart, uvEnd, textureSubmesh); } else { uvStart = new Vector2(uvStart.y, uvStart.x); uvEnd = new Vector2(uvEnd.y, uvEnd.x); mesh.AddPlane(w3, w1, w2, w0, uvStart, uvEnd, textureSubmesh); } }
private static void FlatRoof(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int volumeIndex = area.volumes.IndexOf(volume); int numberOfVolumePoints = volume.points.Count; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); //add top base of the flat roof Vector3[] newEndVerts = new Vector3[numberOfVolumePoints]; Vector2[] newEndUVs = new Vector2[numberOfVolumePoints]; int[] tris = new List<int>(area.GetTrianglesBySectorBase(volumeIndex)).ToArray(); int roofTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floor); BuildrTexture texture = data.textures[roofTextureID]; for (int i = 0; i < numberOfVolumePoints; i++) { Vector2z point = area.points[volume.points[i]]; newEndVerts[i] = point.vector3 + volumeFloorHeight; newEndUVs[i] = new Vector2(point.vector2.x / texture.textureUnitSize.x, point.vector2.y / texture.textureUnitSize.y); } AddData(newEndVerts, newEndUVs, tris, design.GetTexture(BuildrRoofDesign.textureNames.floor)); }
public BuildrTexture Duplicate(string newName) { BuildrTexture newTexture = new BuildrTexture(newName); newTexture.tiled = true; newTexture.patterned = false; newTexture.tileUnitUV = _tileUnitUV; newTexture.textureUnitSize = _textureUnitSize; newTexture.tiledX = tiledX; newTexture.tiledY = tiledY; newTexture.maxUVTile = maxUVTile; newTexture.material = new Material(material); newTexture.tiledTexture = tiledTexture; newTexture.door = door; newTexture.window = window; newTexture.wall = wall; newTexture.roof = roof; newTexture.proceduralMaterial = _proceduralMaterial; newTexture.userMaterial = _userMaterial; return newTexture; }
public static void Pack(BuildrData data) { data.texturesNotPacked.Clear(); data.texturesPacked.Clear(); int numberOfTextures = data.textures.Count; List <Texture2D> useTextures = new List <Texture2D>(numberOfTextures); List <int> texturePacked = new List <int>(); for (int t = 0; t < numberOfTextures; t++) { BuildrTexture texture = data.textures[t]; //Debug.Log(texture.name+" "+texture.tiled); if (texture.tiled) { int textureWidth = texture.texture.width; int textureHeight = texture.texture.height; int targetTextureWidth = Mathf.RoundToInt(textureWidth * texture.maxUVTile.x); int targetTextureHeight = Mathf.RoundToInt(textureHeight * texture.maxUVTile.y); float resizeToLargest = Mathf.Min((float)MAX_SINGLE_TEXTURE_SIZE / (float)targetTextureWidth, (float)MAX_SINGLE_TEXTURE_SIZE / (float)targetTextureHeight, 1); //ensure texture fits smallest size int useTextureWidth = Mathf.RoundToInt(resizeToLargest * targetTextureWidth); int useTextureHeight = Mathf.RoundToInt(resizeToLargest * targetTextureHeight); if (useTextureWidth == 0 || useTextureHeight == 0) //texture no used on model { data.texturesNotPacked.Add(t); continue; } Texture2D useTexture = new Texture2D(useTextureWidth, useTextureHeight); Color32[] textureBlock = texture.texture.GetPixels32(); Color32[] useBlock = new Color32[useTextureWidth * useTextureHeight]; //paint the textures onto a new texture canvas for (int x = 0; x < useTextureWidth; x++) { for (int y = 0; y < useTextureHeight; y++) { int tx = Mathf.RoundToInt((x / resizeToLargest) % (textureWidth - 1)); int ty = Mathf.RoundToInt((y / resizeToLargest) % (textureHeight - 1)); int useIndex = x + y * useTextureWidth; int tIndex = tx + ty * textureWidth; useBlock[useIndex] = textureBlock[tIndex]; } } useTexture.SetPixels32(useBlock); useTexture.Apply(); useTexture.Compress(true); useTextures.Add(useTexture); texturePacked.Add(t); //Debug.Log(texture.name+" "+useTextureWidth+" "+useTextureHeight); } else { int useTextureWidth = texture.texture.width; int useTextureHeight = texture.texture.height; Texture2D useTexture = new Texture2D(useTextureWidth, useTextureHeight); useTexture.SetPixels32(texture.texture.GetPixels32()); useTexture.Apply(); useTexture.Compress(true); useTextures.Add(useTexture); texturePacked.Add(t); //Debug.Log(texture.name+" "+useTextureWidth+" "+useTextureHeight); } } Texture2D textureAtlas = new Texture2D(1, 1); Rect[] outputRect = textureAtlas.PackTextures(useTextures.ToArray(), PADDING, PACKED_SIZE, false); //remove textures from memory if (data.textureAtlas != null) { Object.DestroyImmediate(data.textureAtlas); } while (useTextures.Count > 0) { Object.DestroyImmediate(useTextures[0]); useTextures.RemoveAt(0); } data.textureAtlas = textureAtlas; data.texturesPacked = texturePacked; data.atlasCoords = outputRect; System.GC.Collect(); }
private void GenerateData() { string[] paths = Directory.GetFiles("Assets/Buildr/Textures"); textures.Clear(); foreach (string path in paths) { if (path.Contains(".meta")) continue; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)); if (texture != null) { string[] splits = path.Split(filenameDelimiters); BuildrTexture bTexture = new BuildrTexture(splits[splits.Length - 1]); bTexture.texture = texture; textures.Add(bTexture); } } }
private static void Sawtooth(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; int[] pointIndexes = new int[4]; switch (design.direction) { case 0: pointIndexes = new int[4] { 0, 1, 2, 3 }; break; case 1: pointIndexes = new int[4] { 1, 2, 3, 0 }; break; case 2: pointIndexes = new int[4] { 2, 3, 0, 1 }; break; case 3: pointIndexes = new int[4] { 3, 0, 1, 2 }; break; } Vector3[] basepoints = new Vector3[4]; Vector3[] points = new Vector3[6]; for (int i = 0; i < design.sawtoothTeeth; i++) { Vector3 toothBaseMovementA = (area.points[volume.points[pointIndexes[3]]].vector3 - area.points[volume.points[pointIndexes[0]]].vector3).normalized; float roofDepthA = Vector3.Distance(area.points[volume.points[pointIndexes[3]]].vector3, area.points[volume.points[pointIndexes[0]]].vector3); float toothDepthA = roofDepthA / design.sawtoothTeeth; Vector3 toothVectorA = toothBaseMovementA * toothDepthA; Vector3 toothBaseMovementB = (area.points[volume.points[pointIndexes[2]]].vector3 - area.points[volume.points[pointIndexes[1]]].vector3).normalized; float roofDepthB = Vector3.Distance(area.points[volume.points[pointIndexes[2]]].vector3, area.points[volume.points[pointIndexes[1]]].vector3); float toothDepthB = roofDepthB / design.sawtoothTeeth; Vector3 toothVectorB = toothBaseMovementB * toothDepthB; basepoints[0] = area.points[volume.points[pointIndexes[0]]].vector3 + toothVectorA * i; basepoints[1] = area.points[volume.points[pointIndexes[1]]].vector3 + toothVectorB * i; basepoints[2] = basepoints[1] + toothVectorB; basepoints[3] = basepoints[0] + toothVectorA; points[0] = basepoints[0] + volumeFloorHeight; points[1] = basepoints[1] + volumeFloorHeight; points[2] = basepoints[2] + volumeFloorHeight; points[3] = basepoints[3] + volumeFloorHeight; points[4] = basepoints[2] + volumeFloorHeight + ridgeVector; points[5] = basepoints[3] + volumeFloorHeight + ridgeVector; //top int subMeshTop = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flippedTop = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, points[0], points[1], points[5], points[4], subMeshTop, flippedTop); //window int subMeshWindow = design.GetTexture(BuildrRoofDesign.textureNames.window); bool flippedWindow = design.IsFlipped(BuildrRoofDesign.textureNames.window); AddPlane(design, points[2], points[3], points[4], points[5], subMeshWindow, flippedWindow); //sides Vector3[] vertsA = new Vector3[3] { points[1], points[2], points[4] }; Vector3[] vertsB = new Vector3[3] { points[0], points[3], points[5] }; float uvWdith = Vector3.Distance(points[0], points[3]); float uvHeight = design.height; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.wall); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdith *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdith = Mathf.Ceil(uvWdith / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdith = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvs = new Vector2[3] { new Vector2(0, 0), new Vector2(uvWdith, 0), new Vector2(uvWdith, uvHeight) }; int[] triA = new int[3] { 1, 0, 2 }; int[] triB = new int[3] { 0, 1, 2 }; AddData(vertsA, uvs, triA, subMesh); AddData(vertsB, uvs, triB, subMesh); } }
private static void GetTextures(BuildrData data) { List<BuildrTexture> walltextures = new List<BuildrTexture>(); List<BuildrTexture> windowtextures = new List<BuildrTexture>(); List<BuildrTexture> doortextures = new List<BuildrTexture>(); List<BuildrTexture> rooftextures = new List<BuildrTexture>(); XmlNodeList xmlTextures = null; string textureFilePath = data.generatorConstraints.texturePackXML; if (File.Exists(textureFilePath)) { XmlDocument xml = new XmlDocument(); StreamReader sr = new StreamReader(textureFilePath); xml.LoadXml(sr.ReadToEnd()); sr.Close(); xmlTextures = xml.SelectNodes("data/textures/texture"); if (xmlTextures == null) return; foreach (XmlNode node in xmlTextures) { string filepath = node["filepath"].FirstChild.Value; string[] splits = filepath.Split(filenameDelimiters); BuildrTexture bTexture = new BuildrTexture(splits[splits.Length - 1]); #if UNITY_EDITOR Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(filepath, typeof(Texture2D)); #else Texture2D texture = new WWW (filepath).texture; #endif bTexture.texture = texture; bTexture.tiled = node["tiled"].FirstChild.Value == "True"; bTexture.patterned = node["patterned"].FirstChild.Value == "True"; Vector2 tileUnitUV; tileUnitUV.x = float.Parse(node["tileUnitUVX"].FirstChild.Value); tileUnitUV.y = float.Parse(node["tileUnitUVY"].FirstChild.Value); bTexture.tileUnitUV = tileUnitUV; Vector2 textureUnitSize; textureUnitSize.x = float.Parse(node["textureUnitSizeX"].FirstChild.Value); textureUnitSize.y = float.Parse(node["textureUnitSizeY"].FirstChild.Value); bTexture.textureUnitSize = textureUnitSize; bTexture.tiledX = int.Parse(node["tiledX"].FirstChild.Value); bTexture.tiledY = int.Parse(node["tiledY"].FirstChild.Value); bTexture.door = node["door"].FirstChild.Value == "True"; bTexture.window = node["window"].FirstChild.Value == "True"; bTexture.wall = node["wall"].FirstChild.Value == "True"; bTexture.roof = node["roof"].FirstChild.Value == "True"; if (bTexture.wall) walltextures.Add(bTexture); if (bTexture.window) windowtextures.Add(bTexture); if (bTexture.door) doortextures.Add(bTexture); if (bTexture.roof) rooftextures.Add(bTexture); } } RandomGen rgen = data.generatorConstraints.rgen; wallTexture = walltextures[rgen.OutputRange(0, walltextures.Count - 1)];//wall data.textures.Add(wallTexture); windowTexture = windowtextures[rgen.OutputRange(0, windowtextures.Count - 1)];//window data.textures.Add(windowTexture); roofTexture = rooftextures[rgen.OutputRange(0, rooftextures.Count - 1)];//roof data.textures.Add(roofTexture); doorTexture = doortextures[rgen.OutputRange(0, doortextures.Count - 1)];//door data.textures.Add(doorTexture); groundFloorWindowTexture = windowtextures[rgen.OutputRange(0, windowtextures.Count - 1)];//window data.textures.Add(groundFloorWindowTexture); }
public static void InspectorGUI(BuildrEditMode _editMode, BuildrData _data) { data = _data; BuildrTexture[] textures = data.textures.ToArray(); int numberOfTextures = textures.Length; selectedTexture = Mathf.Clamp(selectedTexture, 0, numberOfTextures - 1); int currentSelectedTexture = selectedTexture;//keep tack of what we had selected to reset fields if changed Undo.RecordObject(data, "Texture Modified"); if (numberOfTextures == 0) { EditorGUILayout.HelpBox("There are no textures to show", MessageType.Info); if (GUILayout.Button("Add New")) { data.textures.Add(new BuildrTexture("new texture " + numberOfTextures)); numberOfTextures++; selectedTexture = numberOfTextures - 1; } return; } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture", GUILayout.Width(75)); string[] textureNames = new string[numberOfTextures]; for (int t = 0; t < numberOfTextures; t++) { textureNames[t] = textures[t].name; } selectedTexture = EditorGUILayout.Popup(selectedTexture, textureNames); EditorGUILayout.EndHorizontal(); BuildrTexture bTexture = textures[selectedTexture]; EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("Add New", GUILayout.Width(81))) { data.textures.Add(new BuildrTexture("new texture " + numberOfTextures)); numberOfTextures++; selectedTexture = numberOfTextures - 1; } if (GUILayout.Button("Duplicate", GUILayout.Width(90))) { data.textures.Add(bTexture.Duplicate()); numberOfTextures++; selectedTexture = numberOfTextures - 1; } if (GUILayout.Button("Delete", GUILayout.Width(71))) { if (EditorUtility.DisplayDialog("Deleting Texture Entry", "Are you sure you want to delete this texture?", "Delete", "Cancel")) { data.RemoveTexture(bTexture); selectedTexture = 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.ImportTextures(xmlPath, _data); textures = data.textures.ToArray(); selectedTexture = 0; GUI.changed = true; } if (GUILayout.Button("Export", GUILayout.Width(71))) { string xmlPath = EditorUtility.SaveFilePanel("Export as...", "Assets/BuildR/Exported/", _data.name + "_textureLibrary", "xml"); if (xmlPath == "") { return; } BuildrXMLExporter.ExportTextures(xmlPath, _data); GUI.changed = true; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); textures = data.textures.ToArray(); textureNames = new string[numberOfTextures]; for (int t = 0; t < numberOfTextures; t++) { textureNames[t] = textures[t].name; } bTexture = textures[selectedTexture];//reassign string textureName = bTexture.name; GUIStyle redText = new GUIStyle(GUI.skin.textField); if (textureName.Contains(" ")) { redText.focused.textColor = Color.red; textureName = EditorGUILayout.TextField("Name", textureName, redText); } else { redText.focused.textColor = defaultCol; textureName = EditorGUILayout.TextField("Name", textureName, redText); } bTexture.name = textureName; bool conflictingName = false; for (int i = 0; i < textureNames.Length; i++) { if (selectedTexture != i) { if (textureNames[i] == bTexture.name) { conflictingName = true; } } } if (conflictingName) { EditorGUILayout.HelpBox("You have named this texture the same as another.", MessageType.Warning); } if (currentSelectedTexture != selectedTexture) { GUIUtility.hotControl = 0; GUIUtility.keyboardControl = 0; } bTexture.type = (BuildrTexture.Types)EditorGUILayout.EnumPopup("Type", bTexture.type); switch (bTexture.type) { case BuildrTexture.Types.Basic: if (bTexture.texture != null) { string texturePath = AssetDatabase.GetAssetPath(bTexture.texture); TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath); if (!textureImporter.isReadable) { EditorGUILayout.HelpBox("The texture you have selected is not readable." + "\nPlease select the readable checkbox under advanced texture settings." + "\nOr move this texture to the BuildR texture folder and reimport.", MessageType.Error); } } //Shader Time Shader[] tempshaders = (Shader[])Resources.FindObjectsOfTypeAll(typeof(Shader)); List <string> shaderNames = new List <string>(ShaderProperties.NAMES); foreach (Shader shader in tempshaders) { if (!string.IsNullOrEmpty(shader.name) && !shader.name.StartsWith("__") && !shader.name.Contains("hidden")) { shaderNames.Add(shader.name); } } int selectedShaderIndex = shaderNames.IndexOf(bTexture.material.shader.name); int newSelectedShaderIndex = EditorGUILayout.Popup("Shader", selectedShaderIndex, shaderNames.ToArray()); if (selectedShaderIndex != newSelectedShaderIndex) { bTexture.material.shader = Shader.Find(shaderNames[newSelectedShaderIndex]); } Shader selectedShader = bTexture.material.shader; int propertyCount = ShaderUtil.GetPropertyCount(selectedShader); for (int s = 0; s < propertyCount; s++) { ShaderUtil.ShaderPropertyType propertyTpe = ShaderUtil.GetPropertyType(selectedShader, s); string shaderPropertyName = ShaderUtil.GetPropertyName(selectedShader, s); switch (propertyTpe) { case ShaderUtil.ShaderPropertyType.TexEnv: Texture shaderTexture = bTexture.material.GetTexture(shaderPropertyName); Texture newShaderTexture = (Texture)EditorGUILayout.ObjectField(shaderPropertyName, shaderTexture, typeof(Texture), false); if (shaderTexture != newShaderTexture) { bTexture.material.SetTexture(shaderPropertyName, newShaderTexture); } break; case ShaderUtil.ShaderPropertyType.Color: Color shaderColor = bTexture.material.GetColor(shaderPropertyName); Color newShaderColor = EditorGUILayout.ColorField(shaderPropertyName, shaderColor); if (shaderColor != newShaderColor) { bTexture.material.SetColor(shaderPropertyName, newShaderColor); } break; case ShaderUtil.ShaderPropertyType.Float: float shaderFloat = bTexture.material.GetFloat(shaderPropertyName); float newShaderFloat = EditorGUILayout.FloatField(shaderPropertyName, shaderFloat); if (shaderFloat != newShaderFloat) { bTexture.material.SetFloat(shaderPropertyName, newShaderFloat); } break; case ShaderUtil.ShaderPropertyType.Range: float shaderRange = bTexture.material.GetFloat(shaderPropertyName); float rangeMin = ShaderUtil.GetRangeLimits(selectedShader, s, 1); float rangeMax = ShaderUtil.GetRangeLimits(selectedShader, s, 2); float newShaderRange = EditorGUILayout.Slider(shaderPropertyName, shaderRange, rangeMin, rangeMax); if (shaderRange != newShaderRange) { bTexture.material.SetFloat(shaderPropertyName, newShaderRange); } break; case ShaderUtil.ShaderPropertyType.Vector: Vector3 shaderVector = bTexture.material.GetVector(shaderPropertyName); Vector3 newShaderVector = EditorGUILayout.Vector3Field(shaderPropertyName, shaderVector); if (shaderVector != newShaderVector) { bTexture.material.SetVector(shaderPropertyName, newShaderVector); } break; } } bool tiled = EditorGUILayout.Toggle("Is Tiled", bTexture.tiled); if (tiled != bTexture.tiled) { bTexture.tiled = tiled; } if (bTexture.tiled) { bool patterned = EditorGUILayout.Toggle("Has Pattern", bTexture.patterned); if (patterned != bTexture.patterned) { bTexture.patterned = patterned; } } else { bTexture.patterned = false; } if (bTexture.texture == null) { return; } Vector2 textureUnitSize = bTexture.textureUnitSize; if (bTexture.tiled) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("texture width", GUILayout.Width(75)); //, GUILayout.Width(42)); textureUnitSize.x = EditorGUILayout.FloatField(bTexture.textureUnitSize.x, GUILayout.Width(25)); EditorGUILayout.LabelField("metres", GUILayout.Width(40)); //, GUILayout.Width(42)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("texture height", GUILayout.Width(75));//, GUILayout.Width(42)); textureUnitSize.y = EditorGUILayout.FloatField(bTexture.textureUnitSize.y, GUILayout.Width(25)); EditorGUILayout.LabelField("metres", GUILayout.Width(40)); EditorGUILayout.EndHorizontal(); if (bTexture.textureUnitSize != textureUnitSize) { bTexture.textureUnitSize = textureUnitSize; } } Vector2 tileUnitSize = bTexture.tileUnitUV; if (bTexture.patterned) { float minWidth = 2 / bTexture.texture.width; float minHeight = 2 / bTexture.texture.height; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("unit width", GUILayout.Width(75)); float tileUnitSizex = EditorGUILayout.Slider(tileUnitSize.x, minWidth, 1.0f); if (tileUnitSizex != tileUnitSize.x) { tileUnitSize.x = tileUnitSizex; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("unit height", GUILayout.Width(75)); float tileUnitSizey = EditorGUILayout.Slider(tileUnitSize.y, minHeight, 1.0f); if (tileUnitSizey != tileUnitSize.y) { tileUnitSize.y = tileUnitSizey; } EditorGUILayout.EndHorizontal(); bTexture.tileUnitUV = tileUnitSize; EditorGUILayout.Space(); } const int previewTextureUnitSize = 120; const int previewTileUnitSize = 59; const int previewTileUnitPadding = 2; const int previewPadding = 25; EditorGUILayout.BeginHorizontal(); if (bTexture.tiled) { EditorGUILayout.LabelField("1 Metre Squared", GUILayout.Width(previewTextureUnitSize)); } GUILayout.Space(previewPadding); if (bTexture.patterned) { EditorGUILayout.LabelField("Texture Pattern Units", GUILayout.Width(previewTileUnitSize * 2)); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); if (Event.current.type == EventType.Repaint) { texturePreviewPostion = GUILayoutUtility.GetLastRect(); } if (bTexture.tiled) { Rect previewRect = new Rect(texturePreviewPostion.x, texturePreviewPostion.y, previewTextureUnitSize, previewTextureUnitSize); Rect sourceRect = new Rect(0, 0, (1.0f / textureUnitSize.x), (1.0f / textureUnitSize.y)); Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } if (bTexture.patterned) { Rect previewRect = new Rect(previewTextureUnitSize + previewPadding, 0, previewTileUnitSize, previewTileUnitSize); Rect sourceRect = new Rect(0, tileUnitSize.y, tileUnitSize.x, tileUnitSize.y); previewRect.x += texturePreviewPostion.x; previewRect.y += texturePreviewPostion.y; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += tileUnitSize.x; previewRect.x += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += -tileUnitSize.x; sourceRect.y += -tileUnitSize.y; previewRect.x += -(previewTileUnitSize + previewTileUnitPadding); previewRect.y += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += tileUnitSize.x; previewRect.x += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } if (!bTexture.tiled) { EditorGUILayout.LabelField("Tile texture"); EditorGUILayout.BeginHorizontal(); int currentXTiles = bTexture.tiledX; GUILayout.Label("tile x", GUILayout.Width(38)); currentXTiles = EditorGUILayout.IntField(currentXTiles, GUILayout.Width(20)); if (GUILayout.Button("+", GUILayout.Width(25))) { currentXTiles++; } EditorGUI.BeginDisabledGroup(currentXTiles < 2); if (GUILayout.Button("-", GUILayout.Width(25))) { currentXTiles--; } EditorGUI.EndDisabledGroup(); bTexture.tiledX = currentXTiles; int currentYTiles = bTexture.tiledY; GUILayout.Label("tile y", GUILayout.Width(38)); currentYTiles = EditorGUILayout.IntField(currentYTiles, GUILayout.Width(20)); if (GUILayout.Button("+", GUILayout.Width(25))) { currentYTiles++; } EditorGUI.BeginDisabledGroup(currentYTiles < 2); if (GUILayout.Button("-", GUILayout.Width(25))) { currentYTiles--; } EditorGUI.EndDisabledGroup(); bTexture.tiledY = currentYTiles; EditorGUILayout.EndHorizontal(); GUILayout.Space(10); EditorGUILayout.Space(); if (Event.current.type == EventType.Repaint) { texturePreviewPostion = GUILayoutUtility.GetLastRect(); } Rect previewRect = new Rect(texturePreviewPostion.x, texturePreviewPostion.y, previewTextureUnitSize, previewTextureUnitSize); Rect sourceRect = new Rect(0, 0, currentXTiles, currentYTiles); Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } GUILayout.Space(previewTextureUnitSize); break; case BuildrTexture.Types.Substance: bTexture.proceduralMaterial = (ProceduralMaterial)EditorGUILayout.ObjectField("Procedural Material", bTexture.proceduralMaterial, typeof(ProceduralMaterial), false); if (bTexture.proceduralMaterial != null) { ProceduralMaterial pMat = bTexture.proceduralMaterial; GUILayout.Label(pMat.GetGeneratedTexture(pMat.mainTexture.name), GUILayout.Width(400)); } else { EditorGUILayout.HelpBox("There is no substance material set.", MessageType.Error); } break; case BuildrTexture.Types.User: bTexture.userMaterial = (Material)EditorGUILayout.ObjectField("User Material", bTexture.userMaterial, typeof(Material), false); if (bTexture.userMaterial != null) { Material mat = bTexture.userMaterial; GUILayout.Label(mat.mainTexture, GUILayout.Width(400)); } else { EditorGUILayout.HelpBox("There is no substance material set.", MessageType.Error); } break; } }
/// <summary> /// Atlas the specified modifySubmeshes using newTextureCoords and textures. /// </summary> /// <param name='modifySubmeshes'> /// Submeshes indicies to atlas. /// </param> /// <param name='newTextureCoords'> /// New texture coords generated from Pack Textures. /// </param> /// <param name='textures'> /// BuildR Textures library reference. /// </param> public void Atlas(int[] modifySubmeshes, Rect[] newTextureCoords, BuildrTexture[] textures) { if (modifySubmeshes.Length == 0) { Debug.Log("No submeshes to atlas!"); return; } List<int> atlasedSubmesh = new List<int>(); int numberOfSubmeshesToModify = modifySubmeshes.Length; for (int s = 0; s < numberOfSubmeshesToModify; s++) { int submeshIndex = modifySubmeshes[s]; Rect textureRect = newTextureCoords[s]; if (!subTriangles.ContainsKey(submeshIndex)) continue; int[] submeshIndices = subTriangles[submeshIndex].ToArray(); subTriangles.Remove(submeshIndex); atlasedSubmesh.AddRange(submeshIndices); BuildrTexture bTexture = textures[submeshIndex]; List<int> ModifiedUVs = new List<int>(); foreach (int index in submeshIndices) { if (ModifiedUVs.Contains(index)) continue;//don't move the UV more than once Vector2 uvCoords = uv[index]; float xUV = uvCoords.x / bTexture.maxUVTile.x; float yUV = uvCoords.y / bTexture.maxUVTile.y; if (xUV > 1) { bTexture.maxUVTile.x = uvCoords.x; xUV = 1.0f; } if (yUV > 1) { bTexture.maxUVTile.y = uvCoords.y; yUV = 1; } uvCoords.x = Mathf.Lerp(textureRect.xMin, textureRect.xMax, xUV); uvCoords.y = Mathf.Lerp(textureRect.yMin, textureRect.yMax, yUV); if (float.IsNaN(uvCoords.x)) { uvCoords.x = 1; } if (float.IsNaN(uvCoords.y)) { uvCoords.y = 1; } uv[index] = uvCoords; ModifiedUVs.Add(index);//keep a record of moved UVs } } subMeshCount = subMeshCount - modifySubmeshes.Length + 1; subTriangles.Add(modifySubmeshes[0], atlasedSubmesh); }
// private static float timestart; /// <summary> /// Custom BuildR texture packer. Uses the BuildR Data class to create a single texture used by the generated building, taking into account tiling. /// </summary> /// <param name="data">BuildR Building Data</param> public static void Pack(BuildrData data) { // timestart = Time.realtimeSinceStartup; data.texturesNotPacked.Clear(); data.texturesPacked.Clear(); int numberOfTextures = data.textures.Count; List <Rect> packedTexturePositions = new List <Rect>(); List <int> texturePacked = new List <int>(); for (int t = 0; t < numberOfTextures; t++) { BuildrTexture texture = data.textures[t]; if (texture.tiled) { int textureWidth = texture.texture.width; int textureHeight = texture.texture.height; int targetTextureWidth = Mathf.RoundToInt(textureWidth * texture.maxUVTile.x); int targetTextureHeight = Mathf.RoundToInt(textureHeight * texture.maxUVTile.y); float resizeToLargest = Mathf.Min((float)MAX_SOURCE_TEXTURE_SIZE / (float)targetTextureWidth, (float)MAX_SOURCE_TEXTURE_SIZE / (float)targetTextureHeight, 1);//ensure texture fits smallest size int useTextureWidth = Mathf.RoundToInt(resizeToLargest * targetTextureWidth); int useTextureHeight = Mathf.RoundToInt(resizeToLargest * targetTextureHeight); if (useTextureWidth == 0 || useTextureHeight == 0)//texture no used on model { data.texturesNotPacked.Add(t); continue; } packedTexturePositions.Add(new Rect(0, 0, useTextureWidth, useTextureHeight)); texturePacked.Add(t); } else { int useTextureWidth = texture.texture.width; int useTextureHeight = texture.texture.height; packedTexturePositions.Add(new Rect(0, 0, useTextureWidth, useTextureHeight)); texturePacked.Add(t); } } int atlasedTextureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING); //determine the resize scale and apply that to the rects float packedScale = 1; int numberOfRects = packedTexturePositions.Count; if (atlasedTextureWidth > MAXIMUM_TEXTURESIZE) { packedScale = MAXIMUM_TEXTURESIZE / (float)atlasedTextureWidth; for (int i = 0; i < numberOfRects; i++) { Rect thisRect = packedTexturePositions[i]; thisRect.x *= packedScale; thisRect.y *= packedScale; thisRect.width *= packedScale; thisRect.height *= packedScale; packedTexturePositions[i] = thisRect; } atlasedTextureWidth = Mathf.RoundToInt(packedScale * atlasedTextureWidth); } else { atlasedTextureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(atlasedTextureWidth - 1, 2)) + 1));//find the next power of two } int textureSize = atlasedTextureWidth * atlasedTextureWidth; Color32[] colourArray = new Color32[textureSize]; //Build colour array for (int t = 0; t < numberOfTextures; t++) { BuildrTexture texture = data.textures[t]; Rect packedPosition = packedTexturePositions[t]; int targetTextureWidth = (int)packedPosition.width; int targetTextureHeight = (int)packedPosition.height; int sourceTextureWidth = texture.texture.width; int sourceTextureHeight = texture.texture.height; // int sourceTextureSize = sourceTextureWidth * sourceTextureHeight; int paintTextureWidth = Mathf.RoundToInt(targetTextureWidth / (texture.tiled ? texture.maxUVTile.x : texture.tiledX)); int paintTextureHeight = Mathf.RoundToInt(targetTextureHeight / (texture.tiled ? texture.maxUVTile.y : texture.tiledY)); int paintTextureSize = paintTextureWidth * paintTextureHeight; Color32[] paintColourArray = TextureScale.NearestNeighbourSample(texture.texture.GetPixels32(), sourceTextureWidth, sourceTextureHeight, paintTextureWidth, paintTextureHeight); for (int x = 0; x < targetTextureWidth; x++) { for (int y = 0; y < targetTextureHeight; y++) { int drawX = Mathf.FloorToInt(x + packedPosition.x); int drawY = Mathf.FloorToInt(y + packedPosition.y); int colourIndex = drawX + drawY * atlasedTextureWidth; int sx = x % paintTextureWidth; int sy = y % paintTextureHeight; int paintIndex = sx + sy * paintTextureWidth; if (paintIndex >= paintTextureSize) { Debug.Log("Source Index too big " + sx + " " + sy + " " + paintTextureWidth + " " + paintTextureSize + " " + texture.maxUVTile + " " + texture.name); } Color32 sourceColour = paintColourArray[paintIndex]; if (colourIndex >= textureSize) { Debug.Log("Output Index Too big " + drawX + " " + drawY + " " + colourIndex + " " + textureSize + " " + packedPosition); } colourArray[colourIndex] = sourceColour; } } } Texture2D packedTexture = new Texture2D(atlasedTextureWidth, atlasedTextureWidth, TextureFormat.ARGB32, true); packedTexture.filterMode = FilterMode.Bilinear; packedTexture.SetPixels32(colourArray); packedTexture.Apply(true, false); //remove textures from memory if (data.textureAtlas != null) { DestroyImmediate(data.textureAtlas); } data.textureAtlas = packedTexture; data.texturesPacked = texturePacked; data.atlasCoords = RectanglePack.ConvertToUVSpace(packedTexturePositions.ToArray(), atlasedTextureWidth); System.GC.Collect(); //Debug.Log("BuildR Texutre Pack Complete: " + (Time.realtimeSinceStartup - timestart)+" sec"); }
private static void GenerateFacades(BuildrData data) { 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 != null) ? (doorTexture.texture.width / (float)doorTexture.texture.height) * doorBay.openingHeight : doorBay.openingHeight * 0.5f; 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.Count; 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); 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); 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 InspectorGUI(BuildrEditMode editMode, BuildrData _data) { data = _data; Undo.RecordObject(data, "Roof Modified"); BuildrRoofDesign[] roofs = data.roofs.ToArray(); int numberOfRoofs = roofs.Length; selectedRoof = Mathf.Clamp(selectedRoof, 0, numberOfRoofs - 1); if (GUILayout.Button("Add new roof design")) { data.roofs.Add(new BuildrRoofDesign("new roof " + numberOfRoofs)); roofs = data.roofs.ToArray(); numberOfRoofs++; selectedRoof = numberOfRoofs - 1; } if (numberOfRoofs == 0) { EditorGUILayout.HelpBox("There are no roof designs to show", MessageType.Info); return; } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Design: ", GUILayout.Width(75)); string[] roofNames = new string[numberOfRoofs]; for (int f = 0; f < numberOfRoofs; f++) { roofNames[f] = roofs[f].name; } selectedRoof = EditorGUILayout.Popup(selectedRoof, roofNames); BuildrRoofDesign bRoof = roofs[selectedRoof]; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Delete", GUILayout.Width(75))) { if (EditorUtility.DisplayDialog("Deleting Roof Design Entry", "Are you sure you want to delete this roof?", "Delete", "Cancel")) { data.RemoveRoofDesign(bRoof); selectedRoof = 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.ImportRoofs(xmlPath, _data); GUI.changed = true; } if (GUILayout.Button("Export", GUILayout.Width(71))) { string xmlPath = EditorUtility.SaveFilePanel("Export as...", "Assets/BuildR/Exported/", _data.name + "_roofLibrary", "xml"); if (xmlPath == "") { return; } BuildrXMLExporter.ExportRoofs(xmlPath, _data); GUI.changed = true; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Name: ", GUILayout.Width(75)); bRoof.name = EditorGUILayout.TextField(bRoof.name); EditorGUILayout.EndHorizontal(); //ROOF STYLE EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Style: ", GUILayout.Width(75)); BuildrRoofDesign.styles bRoofstyle = (BuildrRoofDesign.styles)EditorGUILayout.EnumPopup(bRoof.style); if (bRoofstyle != bRoof.style) { bRoof.style = bRoofstyle; } EditorGUILayout.EndHorizontal(); if (bRoof.style != BuildrRoofDesign.styles.flat && bRoof.style != BuildrRoofDesign.styles.mansard && bRoof.style != BuildrRoofDesign.styles.steepled && bRoof.style != BuildrRoofDesign.styles.hipped) { EditorGUILayout.HelpBox("Please note that this design can only be used on sections with 4 points." + "\nComplex sections can only use the Flat, Mansard and Steeple designs.", MessageType.Warning); } if (bRoof.style != BuildrRoofDesign.styles.flat) { bRoof.height = Mathf.Max(EditorGUILayout.FloatField("Height", bRoof.height), 0); } if (bRoof.style == BuildrRoofDesign.styles.mansard) { bRoof.floorDepth = Mathf.Max(EditorGUILayout.FloatField("Base Depth", bRoof.floorDepth), 0); bRoof.depth = Mathf.Max(EditorGUILayout.FloatField("Top Depth", bRoof.depth), 0); } if (bRoof.style == BuildrRoofDesign.styles.barrel) { bRoof.barrelSegments = Mathf.Max(EditorGUILayout.IntField("Barrel Segments", bRoof.barrelSegments), 3); } if (bRoof.style == BuildrRoofDesign.styles.barrel || bRoof.style == BuildrRoofDesign.styles.gabled || bRoof.style == BuildrRoofDesign.styles.hipped) { //two directions of the ridge bRoof.direction = Mathf.Clamp(bRoof.direction, 0, 1); string[] options = new string[2] { "short", "long" }; bRoof.direction = EditorGUILayout.Popup(bRoof.direction, options); } if (bRoof.style == BuildrRoofDesign.styles.leanto || bRoof.style == BuildrRoofDesign.styles.sawtooth) { //four directions of the ridge bRoof.direction = Mathf.Clamp(bRoof.direction, 0, 3); string[] options = new string[4] { "left", "up", "right", "down" }; bRoof.direction = EditorGUILayout.Popup(bRoof.direction, options); } if (bRoof.style == BuildrRoofDesign.styles.sawtooth) { bRoof.sawtoothTeeth = Mathf.Max(EditorGUILayout.IntField("Number of 'teeth'", bRoof.sawtoothTeeth), 2); } //PARAPET bool bRoofparapet = EditorGUILayout.Toggle("Has Parapet", bRoof.parapet); if (bRoofparapet != bRoof.parapet) { bRoof.parapet = bRoofparapet; } if (bRoof.parapet) { float bRoofparapetHeight = Mathf.Max(EditorGUILayout.FloatField("Parapet Width", bRoof.parapetHeight), 0); if (bRoofparapetHeight != bRoof.parapetHeight) { bRoof.parapetHeight = bRoofparapetHeight; } float bRoofparapetFrontDepth = Mathf.Max(EditorGUILayout.FloatField("Parapet Front Depth", bRoof.parapetFrontDepth), 0); if (bRoofparapetFrontDepth != bRoof.parapetFrontDepth) { bRoof.parapetFrontDepth = bRoofparapetFrontDepth; } float bRoofparapetBackDepth = Mathf.Max(EditorGUILayout.FloatField("Parapet Back Depth", bRoof.parapetBackDepth), 0); if (bRoofparapetBackDepth != bRoof.parapetBackDepth) { bRoof.parapetBackDepth = bRoofparapetBackDepth; } if (bRoof.parapetStyle == BuildrRoofDesign.parapetStyles.fancy)//NOT IMPLMENTED...YET... { EditorGUILayout.HelpBox("This allows you to specify a model mesh that will be used to create a parapet." + "\nIt should not repeat as Buildr will attempt to repeat the style to fit the length of the facade.", MessageType.Info); bRoof.parapetDesign = (Mesh)EditorGUILayout.ObjectField("Parapet Mesh", bRoof.parapetDesign, typeof(Mesh), false); bRoof.parapetDesignWidth = Mathf.Max(EditorGUILayout.FloatField("Parapet Design Width", bRoof.parapetDesignWidth), 0); } } //DORMERS if (bRoof.style == BuildrRoofDesign.styles.mansard) { bool bRoofhasDormers = EditorGUILayout.Toggle("Has Dormers", bRoof.hasDormers); if (bRoofhasDormers != bRoof.hasDormers) { bRoof.hasDormers = bRoofhasDormers; } if (bRoof.hasDormers) { float bRoofdormerWidth = Mathf.Max(EditorGUILayout.FloatField("Dormer Width", bRoof.dormerWidth), 0); if (bRoofdormerWidth != bRoof.dormerWidth) { bRoof.dormerWidth = bRoofdormerWidth; } float bRoofdormerHeight = Mathf.Clamp(EditorGUILayout.FloatField("Dormer Height", bRoof.dormerHeight), 0, bRoof.height); if (bRoofdormerHeight != bRoof.dormerHeight) { bRoof.dormerHeight = bRoofdormerHeight; } float bRoofdormerRoofHeight = Mathf.Clamp(EditorGUILayout.FloatField("Dormer Roof Height", bRoof.dormerRoofHeight), 0, bRoof.dormerHeight); if (bRoofdormerRoofHeight != bRoof.dormerRoofHeight) { bRoof.dormerRoofHeight = bRoofdormerRoofHeight; } float bRoofminimumDormerSpacing = Mathf.Max(EditorGUILayout.FloatField("Dormer Minimum Spacing", bRoof.minimumDormerSpacing), 0); if (bRoofminimumDormerSpacing != bRoof.minimumDormerSpacing) { bRoof.minimumDormerSpacing = bRoofminimumDormerSpacing; } float bRoofdormerHeightRatio = EditorGUILayout.Slider("Dormer Height Ratio", bRoof.dormerHeightRatio, 0, 1); if (bRoofdormerHeightRatio != bRoof.dormerHeightRatio) { bRoof.dormerHeightRatio = bRoofdormerHeightRatio; } } } //TEXTURES int numberOfTextures = data.textures.Count; string[] textureNames = new string[numberOfTextures]; for (int t = 0; t < numberOfTextures; t++) { textureNames[t] = data.textures[t].name; } int numberOfTextureSlots = bRoof.numberOfTextures; string[] titles = new string[numberOfTextureSlots]; for (int brt = 0; brt < numberOfTextureSlots; brt++) { titles[brt] = ((BuildrRoofDesign.textureNames)(brt)).ToString(); } editTextureOnRoof = EditorGUILayout.Popup("Texture Surface:", editTextureOnRoof, titles); int selectedRoofTexture = EditorGUILayout.Popup("Selected Texture:", bRoof.textureValues[editTextureOnRoof], textureNames); if (selectedRoofTexture != bRoof.textureValues[editTextureOnRoof]) { bRoof.textureValues[editTextureOnRoof] = selectedRoofTexture; } BuildrTexture bTexture = data.textures[bRoof.textureValues[editTextureOnRoof]]; 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[bRoof.textureValues[editTextureOnRoof]] + "', assign one in the Textures menu above", MessageType.Warning); } bRoof.flipValues[editTextureOnRoof] = EditorGUILayout.Toggle("Flip 90\u00B0", bRoof.flipValues[editTextureOnRoof]); EditorGUILayout.EndHorizontal(); }
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]--; } } }
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"); }
private static void Gabled(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; Vector3[] basePoints = new Vector3[4]; if (design.direction == 0) { basePoints[0] = area.points[volume.points[0]].vector3 + volumeFloorHeight; basePoints[1] = area.points[volume.points[1]].vector3 + volumeFloorHeight; basePoints[2] = area.points[volume.points[2]].vector3 + volumeFloorHeight; basePoints[3] = area.points[volume.points[3]].vector3 + volumeFloorHeight; } else { basePoints[0] = area.points[volume.points[1]].vector3 + volumeFloorHeight; basePoints[1] = area.points[volume.points[2]].vector3 + volumeFloorHeight; basePoints[2] = area.points[volume.points[3]].vector3 + volumeFloorHeight; basePoints[3] = area.points[volume.points[0]].vector3 + volumeFloorHeight; } Vector3 centrePoint = Vector3.zero; for (int l = 0; l < 4; l++) centrePoint += area.points[volume.points[l]].vector3; centrePoint = (centrePoint / 4) + volumeFloorHeight + ridgeVector; Vector3 r0 = Vector3.Lerp(basePoints[0], basePoints[1], 0.5f) + ridgeVector; Vector3 r1 = Vector3.Lerp(basePoints[2], basePoints[3], 0.5f) + ridgeVector; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flipped = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, basePoints[0], r0, basePoints[3], r1, subMesh, flipped);//top AddPlane(design, basePoints[2], r1, basePoints[1], r0, subMesh, flipped);//top Vector3[] vertsA = new Vector3[3] { basePoints[0], basePoints[1], r0 }; Vector3[] vertsB = new Vector3[3] { basePoints[2], basePoints[3], r1 }; float uvWdithA = Vector3.Distance(basePoints[0], basePoints[1]); float uvWdithB = Vector3.Distance(basePoints[2], basePoints[3]); float uvHeight = design.height; subMesh = design.GetTexture(BuildrRoofDesign.textureNames.wall); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdithA *= (1.0f / texture.textureUnitSize.x); uvWdithB *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdithA = Mathf.Ceil(uvWdithA / uvunits.x) * uvunits.x; uvWdithB = Mathf.Ceil(uvWdithB / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdithA = texture.tiledX; uvWdithB = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvsA = new Vector2[3] { new Vector2(-uvWdithA / 2, 0), new Vector2(uvWdithA / 2, 0), new Vector2(0, uvHeight) }; Vector2[] uvsB = new Vector2[3] { new Vector2(-uvWdithB / 2, 0), new Vector2(uvWdithB / 2, 0), new Vector2(0, uvHeight) }; int[] tri = new int[3] { 1, 0, 2 }; AddData(vertsA, uvsA, tri, subMesh); AddData(vertsB, uvsB, tri, subMesh); }
private static void LeanTo(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; int[] pointIndexes = new int[4]; switch (design.direction) { case 0: pointIndexes = new int[4] { 0, 1, 2, 3 }; break; case 1: pointIndexes = new int[4] { 1, 2, 3, 0 }; break; case 2: pointIndexes = new int[4] { 2, 3, 0, 1 }; break; case 3: pointIndexes = new int[4] { 3, 0, 1, 2 }; break; } Vector3[] points = new Vector3[6]; points[0] = area.points[volume.points[pointIndexes[0]]].vector3 + volumeFloorHeight; points[1] = area.points[volume.points[pointIndexes[1]]].vector3 + volumeFloorHeight; points[2] = area.points[volume.points[pointIndexes[2]]].vector3 + volumeFloorHeight; points[3] = area.points[volume.points[pointIndexes[3]]].vector3 + volumeFloorHeight; points[4] = area.points[volume.points[pointIndexes[2]]].vector3 + volumeFloorHeight + ridgeVector; points[5] = area.points[volume.points[pointIndexes[3]]].vector3 + volumeFloorHeight + ridgeVector; //top int subMeshTop = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flippedTop = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, points[0], points[1], points[5], points[4], subMeshTop, flippedTop); //window int subMeshWindow = design.GetTexture(BuildrRoofDesign.textureNames.window); bool flippedWindow = design.IsFlipped(BuildrRoofDesign.textureNames.window); AddPlane(design, points[2], points[3], points[4], points[5], subMeshWindow, flippedWindow); //sides Vector3[] vertsA = new Vector3[3] { points[1], points[2], points[4] }; Vector3[] vertsB = new Vector3[3] { points[0], points[3], points[5] }; float uvWdith = Vector3.Distance(points[0], points[3]); float uvHeight = design.height; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.wall); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdith *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdith = Mathf.Ceil(uvWdith / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdith = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvs = new Vector2[3] { new Vector2(0, 0), new Vector2(uvWdith, 0), new Vector2(uvWdith, uvHeight) }; if (!design.IsFlipped(BuildrRoofDesign.textureNames.wall)) uvs = new Vector2[3] { new Vector2(uvWdith, 0), new Vector2(0, 0), new Vector2(uvHeight, uvWdith / 2) }; int[] triA = new int[3] { 1, 0, 2 }; int[] triB = new int[3] { 0, 1, 2 }; AddData(vertsA, uvs, triA, subMesh); AddData(vertsB, uvs, triB, subMesh); }
private static void GetTextures(BuildrData data) { List <BuildrTexture> walltextures = new List <BuildrTexture>(); List <BuildrTexture> windowtextures = new List <BuildrTexture>(); List <BuildrTexture> doortextures = new List <BuildrTexture>(); List <BuildrTexture> rooftextures = new List <BuildrTexture>(); XmlNodeList xmlTextures = null; string textureFilePath = data.generatorConstraints.texturePackXML; if (File.Exists(textureFilePath)) { XmlDocument xml = new XmlDocument(); StreamReader sr = new StreamReader(textureFilePath); xml.LoadXml(sr.ReadToEnd()); sr.Close(); xmlTextures = xml.SelectNodes("data/textures/texture"); if (xmlTextures == null) { return; } foreach (XmlNode node in xmlTextures) { string filepath = node["filepath"].FirstChild.Value; string[] splits = filepath.Split(filenameDelimiters); BuildrTexture bTexture = new BuildrTexture(splits[splits.Length - 1]); #if UNITY_EDITOR Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(filepath, typeof(Texture2D)); #else Texture2D texture = new WWW(filepath).texture; #endif bTexture.texture = texture; bTexture.tiled = node["tiled"].FirstChild.Value == "True"; bTexture.patterned = node["patterned"].FirstChild.Value == "True"; Vector2 tileUnitUV; tileUnitUV.x = float.Parse(node["tileUnitUVX"].FirstChild.Value); tileUnitUV.y = float.Parse(node["tileUnitUVY"].FirstChild.Value); bTexture.tileUnitUV = tileUnitUV; Vector2 textureUnitSize; textureUnitSize.x = float.Parse(node["textureUnitSizeX"].FirstChild.Value); textureUnitSize.y = float.Parse(node["textureUnitSizeY"].FirstChild.Value); bTexture.textureUnitSize = textureUnitSize; bTexture.tiledX = int.Parse(node["tiledX"].FirstChild.Value); bTexture.tiledY = int.Parse(node["tiledY"].FirstChild.Value); bTexture.door = node["door"].FirstChild.Value == "True"; bTexture.window = node["window"].FirstChild.Value == "True"; bTexture.wall = node["wall"].FirstChild.Value == "True"; bTexture.roof = node["roof"].FirstChild.Value == "True"; if (bTexture.wall) { walltextures.Add(bTexture); } if (bTexture.window) { windowtextures.Add(bTexture); } if (bTexture.door) { doortextures.Add(bTexture); } if (bTexture.roof) { rooftextures.Add(bTexture); } } } RandomGen rgen = data.generatorConstraints.rgen; wallTexture = walltextures[rgen.OutputRange(0, walltextures.Count - 1)];//wall data.textures.Add(wallTexture); windowTexture = windowtextures[rgen.OutputRange(0, windowtextures.Count - 1)];//window data.textures.Add(windowTexture); roofTexture = rooftextures[rgen.OutputRange(0, rooftextures.Count - 1)];//roof data.textures.Add(roofTexture); doorTexture = doortextures[rgen.OutputRange(0, doortextures.Count - 1)];//door data.textures.Add(doorTexture); groundFloorWindowTexture = windowtextures[rgen.OutputRange(0, windowtextures.Count - 1)];//window data.textures.Add(groundFloorWindowTexture); }
/// <summary> /// Atlas the specified modifySubmeshes using newTextureCoords and textures. /// </summary> /// <param name='modifySubmeshes'> /// Submeshes indicies to atlas. /// </param> /// <param name='newTextureCoords'> /// New texture coords generated from Pack Textures. /// </param> /// <param name='textures'> /// BuildR Textures library reference. /// </param> public void Atlas(int[] modifySubmeshes, Rect[] newTextureCoords, BuildrTexture[] textures) { foreach (DynamicMeshGenericMultiMaterial mesh in _meshes) mesh.Atlas(modifySubmeshes, newTextureCoords, textures); }
private void OnGUI() { string asterisk = GUI.changed ? "*" : ""; EditorGUILayout.LabelField("Texture Designs" + asterisk, GUILayout.Height(12), GUILayout.Width(280)); Texture2D facadeTexture = new Texture2D(1, 1); facadeTexture.SetPixel(0, 0, BuildrColours.BLUE); facadeTexture.Apply(); Rect sqrPos = new Rect(0, 0, 0, 0); if (Event.current.type == EventType.Repaint) { sqrPos = GUILayoutUtility.GetLastRect(); } GUI.DrawTexture(sqrPos, facadeTexture); EditorGUI.DropShadowLabel(sqrPos, "Texture Designs" + asterisk); //int currentSelectedTexture = selectedTexture;//keep tack of what we had selected to reset fields if changed int numberOfFiles = xmlfilelist.Count; string[] fileNames = new string[numberOfFiles]; for (int t = 0; t < numberOfFiles; t++) { string filepath = xmlfilelist[t]; string[] filepathsplit = filepath.Split(filenameDelimiters); string displayPath = filepathsplit[filepathsplit.Length - 1]; fileNames[t] = displayPath; } int newSelectedFile = EditorGUILayout.Popup(selectedFile, fileNames); if (newSelectedFile != selectedFile) { selectedFile = newSelectedFile; textureFilePath = xmlfilelist[selectedFile]; CheckData(); selectedTexture = 0;//reset the selected texture to 0 to avoid index out of range... } if (GUILayout.Button("Create New Texture Pack")) { if (EditorUtility.DisplayDialog("New Texture Pack", "Are you sure you want to start a new texture pack.\nAll unsaved data will be shown the door.", "ok, do it!", "no no no no")) { GenerateData(); } } int numberOfTextures = textures.Count; selectedTexture = Mathf.Clamp(selectedTexture, 0, numberOfTextures - 1); EditorGUILayout.BeginHorizontal(); string[] texturePaths = GetTextureFilenames(); string[] textureFilenames = new string[texturePaths.Length]; for (int t = 0; t < texturePaths.Length; t++) { string[] splits = texturePaths[t].Split(filenameDelimiters); textureFilenames[t] = splits[splits.Length - 1]; } addSelectedTexture = EditorGUILayout.Popup(addSelectedTexture, textureFilenames); if (GUILayout.Button("Add New Texture to Pack")) { string path = texturePaths[addSelectedTexture]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)); if (texture != null) { string[] splits = path.Split(filenameDelimiters); BuildrTexture newBTexture = new BuildrTexture(splits[splits.Length - 1]); newBTexture.texture = texture; textures.Add(newBTexture); selectedTexture = textures.Count - 1; } } EditorGUILayout.EndHorizontal(); if (numberOfTextures == 0) { EditorGUILayout.HelpBox("There are no textures to show", MessageType.Info); return; } EditorGUILayout.LabelField("Selected Texture"); EditorGUILayout.BeginHorizontal(); string[] textureNames = new string[numberOfTextures]; for (int t = 0; t < numberOfTextures; t++) { textureNames[t] = textures[t].name; } selectedTexture = EditorGUILayout.Popup(selectedTexture, textureNames); EditorGUI.BeginDisabledGroup(selectedTexture <= 0); if (GUILayout.Button("<", GUILayout.Width(25))) { selectedTexture--; } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(selectedTexture >= numberOfTextures - 1); if (GUILayout.Button(">", GUILayout.Width(25))) { selectedTexture++; } EditorGUI.EndDisabledGroup(); BuildrTexture bTexture = textures[selectedTexture]; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Delete")) { textures.Remove(bTexture); } if (GUILayout.Button("Delete All")) { textures.Clear(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Is Tiled"); bTexture.tiled = EditorGUILayout.Toggle(bTexture.tiled, GUILayout.Width(18)); EditorGUILayout.EndHorizontal(); EditorGUI.BeginDisabledGroup(!bTexture.tiled); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Has Pattern"); bTexture.patterned = EditorGUILayout.Toggle(bTexture.patterned, GUILayout.Width(18)); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); if (!bTexture.tiled) { bTexture.patterned = false; } Vector2 textureUnitSize = bTexture.textureUnitSize; if (bTexture.tiled) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Width", GUILayout.Width(180)); //, GUILayout.Width(42)); textureUnitSize.x = EditorGUILayout.FloatField(bTexture.textureUnitSize.x, GUILayout.Width(35)); EditorGUILayout.LabelField("metres", GUILayout.Width(45)); //, GUILayout.Width(42)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Height", GUILayout.Width(180));//, GUILayout.Width(42)); textureUnitSize.y = EditorGUILayout.FloatField(bTexture.textureUnitSize.y, GUILayout.Width(35)); EditorGUILayout.LabelField("metres", GUILayout.Width(45)); EditorGUILayout.EndHorizontal(); bTexture.textureUnitSize = textureUnitSize; } Vector2 tileUnitSize = bTexture.tileUnitUV; if (bTexture.patterned) { float minWidth = 2 / bTexture.texture.width; float minHeight = 2 / bTexture.texture.height; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Unit Width", GUILayout.Width(75)); tileUnitSize.x = EditorGUILayout.Slider(tileUnitSize.x, minWidth, 1.0f); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Unit Height", GUILayout.Width(75)); tileUnitSize.y = EditorGUILayout.Slider(tileUnitSize.y, minHeight, 1.0f); EditorGUILayout.EndHorizontal(); bTexture.tileUnitUV = tileUnitSize; EditorGUILayout.Space(); } const int previewTextureUnitSize = 120; const int previewTileUnitSize = 59; const int previewTileUnitPadding = 2; const int previewPadding = 25; EditorGUILayout.BeginHorizontal(); if (bTexture.tiled) { EditorGUILayout.LabelField("1 Metre Squared", GUILayout.Width(110)); } GUILayout.Space(previewPadding); if (bTexture.patterned) { EditorGUILayout.LabelField("Texture Pattern Units", GUILayout.Width(120)); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); if (Event.current.type == EventType.Repaint) { texturePreviewPostion = GUILayoutUtility.GetLastRect(); } if (bTexture.tiled) { Rect previewRect = new Rect(texturePreviewPostion.x, texturePreviewPostion.y, previewTextureUnitSize, previewTextureUnitSize); Rect sourceRect = new Rect(0, 0, (1.0f / textureUnitSize.x), (1.0f / textureUnitSize.y)); Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } if (bTexture.patterned) { Rect previewRect = new Rect(previewTextureUnitSize + previewPadding, 0, previewTileUnitSize, previewTileUnitSize); Rect sourceRect = new Rect(0, tileUnitSize.y, tileUnitSize.x, tileUnitSize.y); previewRect.x += texturePreviewPostion.x; previewRect.y += texturePreviewPostion.y; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += tileUnitSize.x; previewRect.x += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += -tileUnitSize.x; sourceRect.y += -tileUnitSize.y; previewRect.x += -(previewTileUnitSize + previewTileUnitPadding); previewRect.y += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += tileUnitSize.x; previewRect.x += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } if (!bTexture.tiled) { //EditorGUILayout.LabelField("Tile texture"); EditorGUILayout.BeginHorizontal(); int currentXTiles = bTexture.tiledX; GUILayout.Label("Texture Tile X"); currentXTiles = EditorGUILayout.IntField(currentXTiles, GUILayout.Width(30)); if (GUILayout.Button("+", GUILayout.Width(25))) { currentXTiles++; } EditorGUI.BeginDisabledGroup(currentXTiles < 2); if (GUILayout.Button("-", GUILayout.Width(25))) { currentXTiles--; } EditorGUI.EndDisabledGroup(); bTexture.tiledX = currentXTiles; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); int currentYTiles = bTexture.tiledY; GUILayout.Label("Texture Tile Y"); currentYTiles = EditorGUILayout.IntField(currentYTiles, GUILayout.Width(30)); if (GUILayout.Button("+", GUILayout.Width(25))) { currentYTiles++; } EditorGUI.BeginDisabledGroup(currentYTiles < 2); if (GUILayout.Button("-", GUILayout.Width(25))) { currentYTiles--; } EditorGUI.EndDisabledGroup(); bTexture.tiledY = currentYTiles; EditorGUILayout.EndHorizontal(); GUILayout.Space(10); EditorGUILayout.Space(); if (Event.current.type == EventType.Repaint) { texturePreviewPostion = GUILayoutUtility.GetLastRect(); } Rect previewRect = new Rect(texturePreviewPostion.x, texturePreviewPostion.y, previewTextureUnitSize, previewTextureUnitSize); Rect sourceRect = new Rect(0, 0, currentXTiles, currentYTiles); Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } GUILayout.Space(previewTextureUnitSize); EditorGUILayout.LabelField("Texture Usage"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Walls"); bTexture.wall = EditorGUILayout.Toggle(bTexture.wall); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Doors"); bTexture.door = EditorGUILayout.Toggle(bTexture.door); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Windows"); bTexture.window = EditorGUILayout.Toggle(bTexture.window); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Roofs"); bTexture.roof = EditorGUILayout.Toggle(bTexture.roof); EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Save Data")) { SaveData(); } if (GUILayout.Button("Save Data As...")) { SaveDataAs(); } }
/// <summary> /// Atlas the specified modifySubmeshes using newTextureCoords and textures. /// </summary> /// <param name='modifySubmeshes'> /// Submeshes indicies to atlas. /// </param> /// <param name='newTextureCoords'> /// New texture coords generated from Pack Textures. /// </param> /// <param name='textures'> /// BuildR Textures library reference. /// </param> public void Atlas(int[] modifySubmeshes, Rect[] newTextureCoords, BuildrTexture[] textures) { if (modifySubmeshes.Length == 0) { Debug.Log("No submeshes to atlas!"); return; } List <int> atlasedSubmesh = new List <int>(); int numberOfSubmeshesToModify = modifySubmeshes.Length; for (int s = 0; s < numberOfSubmeshesToModify; s++) { int submeshIndex = modifySubmeshes[s]; Rect textureRect = newTextureCoords[s]; if (!subTriangles.ContainsKey(submeshIndex)) { continue; } int[] submeshIndices = subTriangles[submeshIndex].ToArray(); subTriangles.Remove(submeshIndex); atlasedSubmesh.AddRange(submeshIndices); BuildrTexture bTexture = textures[submeshIndex]; List <int> ModifiedUVs = new List <int>(); foreach (int index in submeshIndices) { if (ModifiedUVs.Contains(index)) { continue;//don't move the UV more than once } Vector2 uvCoords = uv[index]; float xUV = uvCoords.x / bTexture.maxUVTile.x; float yUV = uvCoords.y / bTexture.maxUVTile.y; if (xUV > 1) { bTexture.maxUVTile.x = uvCoords.x; xUV = 1.0f; } if (yUV > 1) { bTexture.maxUVTile.y = uvCoords.y; yUV = 1; } uvCoords.x = Mathf.Lerp(textureRect.xMin, textureRect.xMax, xUV); uvCoords.y = Mathf.Lerp(textureRect.yMin, textureRect.yMax, yUV); if (float.IsNaN(uvCoords.x)) { uvCoords.x = 1; } if (float.IsNaN(uvCoords.y)) { uvCoords.y = 1; } uv[index] = uvCoords; ModifiedUVs.Add(index);//keep a record of moved UVs } } subMeshCount = subMeshCount - modifySubmeshes.Length + 1; subTriangles.Add(modifySubmeshes[0], atlasedSubmesh); }
public void UpdateInteriors() { while (interiorMeshHolders.Count > 0) { GameObject destroyOld = interiorMeshHolders[0]; interiorMeshHolders.RemoveAt(0); DestroyImmediate(destroyOld); } interiorMeshes.Clear(); if (data.renderInteriors) { int numberOfVolumes = data.plan.numberOfVolumes; for (int v = 0; v < numberOfVolumes; v++) { DynamicMeshGenericMultiMaterialMesh interiorMesh = new DynamicMeshGenericMultiMaterialMesh(); interiorMesh.subMeshCount = data.textures.Count; BuildrVolume volume = _data.plan.volumes[v]; BuildrInteriors.Build(interiorMesh, data, v); interiorMesh.Build(false); List <int> unusedInteriorTextures = interiorMesh.unusedSubmeshes; int numberOfInteriorMaterials = data.textures.Count; List <Material> interiorMaterials = new List <Material>(); for (int m = 0; m < numberOfInteriorMaterials; m++) { if (unusedInteriorTextures.Contains(m)) { continue;//skip, unused } BuildrTexture bTexture = data.textures[m]; interiorMaterials.Add(bTexture.usedMaterial); } int numberOfInteriorMeshes = interiorMesh.meshCount; for (int i = 0; i < numberOfInteriorMeshes; i++) { string meshName = "model interior"; if (numberOfVolumes > 0) { meshName += " volume " + (v + 1); } if (numberOfInteriorMeshes > 1) { meshName += " mesh " + (i + 1); } GameObject newMeshHolder = new GameObject(meshName); newMeshHolder.transform.parent = transform; newMeshHolder.transform.localPosition = Vector3.zero; meshFilt = newMeshHolder.AddComponent <MeshFilter>(); meshRend = newMeshHolder.AddComponent <MeshRenderer>(); meshFilt.mesh = interiorMesh[i].mesh; interiorMeshHolders.Add(newMeshHolder); int numberOfInterior = interiorMeshHolders.Count; for (int m = 0; m < numberOfInterior; m++) { meshRend.sharedMaterials = interiorMaterials.ToArray(); } } interiorMeshes.Add(interiorMesh); if (!volume.generateStairs) { continue; } DynamicMeshGenericMultiMaterialMesh stairwellMesh = new DynamicMeshGenericMultiMaterialMesh(); stairwellMesh.subMeshCount = data.textures.Count; BuildrStairs.Build(stairwellMesh, data, v, BuildrStairs.StairModes.Stepped, true); stairwellMesh.Build(false); List <int> unusedStairTextures = stairwellMesh.unusedSubmeshes; int numberOfStairMaterials = data.textures.Count; List <Material> stairMaterials = new List <Material>(); for (int m = 0; m < numberOfStairMaterials; m++) { if (unusedStairTextures.Contains(m)) { continue;//skip, unused } BuildrTexture bTexture = data.textures[m]; stairMaterials.Add(bTexture.usedMaterial); } int numberOfStairMeshes = stairwellMesh.meshCount; for (int i = 0; i < numberOfStairMeshes; i++) { string meshName = "model stairs"; if (numberOfVolumes > 0) { meshName += " volume " + (v + 1); } if (numberOfStairMeshes > 1) { meshName += " mesh " + (i + 1); } GameObject newMeshHolder = new GameObject(meshName); newMeshHolder.transform.parent = transform; newMeshHolder.transform.localPosition = volume.stairBaseVector[i]; meshFilt = newMeshHolder.AddComponent <MeshFilter>(); meshRend = newMeshHolder.AddComponent <MeshRenderer>(); meshFilt.mesh = stairwellMesh[i].mesh; interiorMeshHolders.Add(newMeshHolder); meshRend.sharedMaterials = stairMaterials.ToArray(); } interiorMeshes.Add(stairwellMesh); } } }
private void OnGUI() { string asterisk = GUI.changed ? "*" : ""; EditorGUILayout.LabelField("Texture Designs" + asterisk, GUILayout.Height(12), GUILayout.Width(280)); Texture2D facadeTexture = new Texture2D(1, 1); facadeTexture.SetPixel(0, 0, BuildrColours.BLUE); facadeTexture.Apply(); Rect sqrPos = new Rect(0, 0, 0, 0); if (Event.current.type == EventType.Repaint) sqrPos = GUILayoutUtility.GetLastRect(); GUI.DrawTexture(sqrPos, facadeTexture); EditorGUI.DropShadowLabel(sqrPos, "Texture Designs" + asterisk); //int currentSelectedTexture = selectedTexture;//keep tack of what we had selected to reset fields if changed int numberOfFiles = xmlfilelist.Count; string[] fileNames = new string[numberOfFiles]; for (int t = 0; t < numberOfFiles; t++) { string filepath = xmlfilelist[t]; string[] filepathsplit = filepath.Split(filenameDelimiters); string displayPath = filepathsplit[filepathsplit.Length-1]; fileNames[t] = displayPath; } int newSelectedFile = EditorGUILayout.Popup(selectedFile, fileNames); if (newSelectedFile != selectedFile) { selectedFile = newSelectedFile; textureFilePath = xmlfilelist[selectedFile]; CheckData(); selectedTexture = 0;//reset the selected texture to 0 to avoid index out of range... } if (GUILayout.Button("Create New Texture Pack")) { if(EditorUtility.DisplayDialog("New Texture Pack","Are you sure you want to start a new texture pack.\nAll unsaved data will be shown the door.","ok, do it!","no no no no")) GenerateData(); } int numberOfTextures = textures.Count; selectedTexture = Mathf.Clamp(selectedTexture, 0, numberOfTextures - 1); EditorGUILayout.BeginHorizontal(); string[] texturePaths = GetTextureFilenames(); string[] textureFilenames = new string[texturePaths.Length]; for (int t = 0; t < texturePaths.Length; t++) { string[] splits = texturePaths[t].Split(filenameDelimiters); textureFilenames[t] = splits[splits.Length - 1]; } addSelectedTexture = EditorGUILayout.Popup(addSelectedTexture, textureFilenames); if (GUILayout.Button("Add New Texture to Pack")) { string path = texturePaths[addSelectedTexture]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)); if (texture != null) { string[] splits = path.Split(filenameDelimiters); BuildrTexture newBTexture = new BuildrTexture(splits[splits.Length - 1]); newBTexture.texture = texture; textures.Add(newBTexture); selectedTexture = textures.Count - 1; } } EditorGUILayout.EndHorizontal(); if (numberOfTextures == 0) { EditorGUILayout.HelpBox("There are no textures to show", MessageType.Info); return; } EditorGUILayout.LabelField("Selected Texture"); EditorGUILayout.BeginHorizontal(); string[] textureNames = new string[numberOfTextures]; for (int t = 0; t < numberOfTextures; t++) textureNames[t] = textures[t].name; selectedTexture = EditorGUILayout.Popup(selectedTexture, textureNames); EditorGUI.BeginDisabledGroup(selectedTexture <= 0); if (GUILayout.Button("<", GUILayout.Width(25))) selectedTexture--; EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(selectedTexture >= numberOfTextures - 1); if (GUILayout.Button(">", GUILayout.Width(25))) selectedTexture++; EditorGUI.EndDisabledGroup(); BuildrTexture bTexture = textures[selectedTexture]; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Delete")) textures.Remove(bTexture); if (GUILayout.Button("Delete All")) textures.Clear(); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Is Tiled"); bTexture.tiled = EditorGUILayout.Toggle(bTexture.tiled, GUILayout.Width(18)); EditorGUILayout.EndHorizontal(); EditorGUI.BeginDisabledGroup(!bTexture.tiled); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Has Pattern"); bTexture.patterned = EditorGUILayout.Toggle(bTexture.patterned, GUILayout.Width(18)); EditorGUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); if (!bTexture.tiled) bTexture.patterned = false; Vector2 textureUnitSize = bTexture.textureUnitSize; if (bTexture.tiled) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Width", GUILayout.Width(180));//, GUILayout.Width(42)); textureUnitSize.x = EditorGUILayout.FloatField(bTexture.textureUnitSize.x, GUILayout.Width(35)); EditorGUILayout.LabelField("metres", GUILayout.Width(45));//, GUILayout.Width(42)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Texture Height", GUILayout.Width(180));//, GUILayout.Width(42)); textureUnitSize.y = EditorGUILayout.FloatField(bTexture.textureUnitSize.y, GUILayout.Width(35)); EditorGUILayout.LabelField("metres", GUILayout.Width(45)); EditorGUILayout.EndHorizontal(); bTexture.textureUnitSize = textureUnitSize; } Vector2 tileUnitSize = bTexture.tileUnitUV; if (bTexture.patterned) { float minWidth = 2 / bTexture.texture.width; float minHeight = 2 / bTexture.texture.height; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Unit Width", GUILayout.Width(75)); tileUnitSize.x = EditorGUILayout.Slider(tileUnitSize.x, minWidth, 1.0f); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Unit Height", GUILayout.Width(75)); tileUnitSize.y = EditorGUILayout.Slider(tileUnitSize.y, minHeight, 1.0f); EditorGUILayout.EndHorizontal(); bTexture.tileUnitUV = tileUnitSize; EditorGUILayout.Space(); } const int previewTextureUnitSize = 120; const int previewTileUnitSize = 59; const int previewTileUnitPadding = 2; const int previewPadding = 25; EditorGUILayout.BeginHorizontal(); if (bTexture.tiled) { EditorGUILayout.LabelField("1 Metre Squared", GUILayout.Width(110)); } GUILayout.Space(previewPadding); if (bTexture.patterned) { EditorGUILayout.LabelField("Texture Pattern Units", GUILayout.Width(120)); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); if (Event.current.type == EventType.Repaint) texturePreviewPostion = GUILayoutUtility.GetLastRect(); if (bTexture.tiled) { Rect previewRect = new Rect(texturePreviewPostion.x, texturePreviewPostion.y, previewTextureUnitSize, previewTextureUnitSize); Rect sourceRect = new Rect(0, 0, (1.0f / textureUnitSize.x), (1.0f / textureUnitSize.y)); Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } if (bTexture.patterned) { Rect previewRect = new Rect(previewTextureUnitSize + previewPadding, 0, previewTileUnitSize, previewTileUnitSize); Rect sourceRect = new Rect(0, tileUnitSize.y, tileUnitSize.x, tileUnitSize.y); previewRect.x += texturePreviewPostion.x; previewRect.y += texturePreviewPostion.y; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += tileUnitSize.x; previewRect.x += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += -tileUnitSize.x; sourceRect.y += -tileUnitSize.y; previewRect.x += -(previewTileUnitSize + previewTileUnitPadding); previewRect.y += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); sourceRect.x += tileUnitSize.x; previewRect.x += previewTileUnitSize + previewTileUnitPadding; Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } if (!bTexture.tiled) { //EditorGUILayout.LabelField("Tile texture"); EditorGUILayout.BeginHorizontal(); int currentXTiles = bTexture.tiledX; GUILayout.Label("Texture Tile X"); currentXTiles = EditorGUILayout.IntField(currentXTiles, GUILayout.Width(30)); if (GUILayout.Button("+", GUILayout.Width(25))) currentXTiles++; EditorGUI.BeginDisabledGroup(currentXTiles < 2); if (GUILayout.Button("-", GUILayout.Width(25))) currentXTiles--; EditorGUI.EndDisabledGroup(); bTexture.tiledX = currentXTiles; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); int currentYTiles = bTexture.tiledY; GUILayout.Label("Texture Tile Y"); currentYTiles = EditorGUILayout.IntField(currentYTiles, GUILayout.Width(30)); if (GUILayout.Button("+", GUILayout.Width(25))) currentYTiles++; EditorGUI.BeginDisabledGroup(currentYTiles < 2); if (GUILayout.Button("-", GUILayout.Width(25))) currentYTiles--; EditorGUI.EndDisabledGroup(); bTexture.tiledY = currentYTiles; EditorGUILayout.EndHorizontal(); GUILayout.Space(10); EditorGUILayout.Space(); if (Event.current.type == EventType.Repaint) texturePreviewPostion = GUILayoutUtility.GetLastRect(); Rect previewRect = new Rect(texturePreviewPostion.x, texturePreviewPostion.y, previewTextureUnitSize, previewTextureUnitSize); Rect sourceRect = new Rect(0, 0, currentXTiles, currentYTiles); Graphics.DrawTexture(previewRect, bTexture.texture, sourceRect, 0, 0, 0, 0); } GUILayout.Space(previewTextureUnitSize); EditorGUILayout.LabelField("Texture Usage"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Walls"); bTexture.wall = EditorGUILayout.Toggle(bTexture.wall); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Doors"); bTexture.door = EditorGUILayout.Toggle(bTexture.door); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Windows"); bTexture.window = EditorGUILayout.Toggle(bTexture.window); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Roofs"); bTexture.roof = EditorGUILayout.Toggle(bTexture.roof); EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Save Data")) SaveData(); if (GUILayout.Button("Save Data As...")) SaveDataAs(); }
/// <summary> /// Atlas the entire mesh using newTextureCoords and textures. /// </summary> /// <param name="newTextureCoords"></param> /// <param name="textures"></param> public void Atlas(Rect[] newTextureCoords, BuildrTexture[] textures) { List<int> keys = new List<int>(subTriangles.Keys); Atlas(keys.ToArray(), newTextureCoords, textures); }
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 void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data) { // timestart = Time.realtimeSinceStartup; data = _data; mesh = _mesh; textures = data.textures.ToArray(); BuildrPlan plan = data.plan; // int facadeIndex = 0; numberOfFacades = 0; int numberOfVolumes = data.plan.numberOfVolumes; //define rectangles that represent the facades packedTexturePositions.Clear(); 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 indexA = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector2z p0 = plan.points[volume.points[indexA]]; Vector2z p1 = plan.points[volume.points[indexB]]; float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER; 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; float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER; if (facadeHeight < 0) { facadeWidth = 0; facadeHeight = 0; } Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight); packedTexturePositions.Add(newFacadeRect); numberOfFacades++; } } //Build ROOF DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh(); dynMeshRoof.name = "Roof Mesh"; dynMeshRoof.subMeshCount = textures.Length; BuildrRoof.Build(dynMeshRoof, data, true); dynMeshRoof.CheckMaxTextureUVs(data); roofTextures.Clear(); roofTextureIndex.Clear(); foreach (BuildrRoofDesign roofDesign in data.roofs) { foreach (int textureIndex in roofDesign.textureValues) { if (!roofTextureIndex.Contains(textureIndex)) { BuildrTexture bTexture = data.textures[textureIndex]; Vector2 largestSubmeshPlaneSize = new Vector2(1, 1); Vector2 minWorldUvSize = dynMeshRoof.MinWorldUvSize(textureIndex); Vector2 maxWorldUvSize = dynMeshRoof.MaxWorldUvSize(textureIndex); largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x; largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y; int roofTextureWidth = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER); int roofTextureHeight = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER); Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight); packedTexturePositions.Add(newRoofTexutureRect); roofTextures.Add(bTexture); roofTextureIndex.Add(textureIndex); } } } //run a custom packer to define their postions textureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING); //determine the resize scale and apply that to the rects packedScale = 1; int numberOfRects = packedTexturePositions.Count; if (textureWidth > MAXIMUM_TEXTURESIZE) { packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth; for (int i = 0; i < numberOfRects; i++) { Rect thisRect = packedTexturePositions[i]; thisRect.x *= packedScale; thisRect.y *= packedScale; thisRect.width *= packedScale; thisRect.height *= packedScale; packedTexturePositions[i] = thisRect; //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]); } textureWidth = Mathf.RoundToInt(packedScale * textureWidth); } else { textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two } textureSize = textureWidth * textureWidth; colourArray = new Color32[textureSize]; //TestRectColours();//this test paints all the facades with rainbow colours - real pretty BuildTextures(); Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true); packedTexture.filterMode = FilterMode.Bilinear; packedTexture.SetPixels32(colourArray); packedTexture.Apply(true, false); if (data.OneDrawCallTexture != null) { Object.DestroyImmediate(data.OneDrawCallTexture); } data.OneDrawCallTexture = packedTexture; data.OneDrawCallTexture.name = "One Draw Call Texture"; int numberOfRoofTextures = roofTextures.Count - 1; List <Rect> facadeTexturePositions = new List <Rect>(packedTexturePositions); Debug.Log(numberOfRoofTextures); facadeTexturePositions.RemoveRange(packedTexturePositions.Count - numberOfRoofTextures, numberOfRoofTextures); BuildrBuilding.Build(mesh, data, facadeTexturePositions.ToArray()); data = null; mesh = null; textures = null; System.GC.Collect(); }
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 Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data) { // timestart = Time.realtimeSinceStartup; data = _data; mesh = _mesh; textures = data.textures.ToArray(); BuildrPlan plan = data.plan; int facadeIndex = 0; numberOfFacades = 0; int numberOfVolumes = data.plan.numberOfVolumes; LogTimer("Start"); //define rectangles that represent the facades packedTexturePositions.Clear(); 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 indexA = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector2z p0 = plan.points[volume.points[indexA]]; Vector2z p1 = plan.points[volume.points[indexB]]; float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER; 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; float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER; if (facadeHeight < 0) { facadeWidth = 0; facadeHeight = 0; } Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight); packedTexturePositions.Add(newFacadeRect); numberOfFacades++; } } //Build ROOF DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh(); dynMeshRoof.name = "Roof Mesh"; dynMeshRoof.subMeshCount = textures.Length; BuildrRoof.Build(dynMeshRoof, data, true); dynMeshRoof.CheckMaxTextureUVs(data); LogTimer("Roof A"); roofTextures.Clear(); roofTextureIndex.Clear(); foreach (BuildrRoofDesign roofDesign in data.roofs) { foreach (int textureIndex in roofDesign.textureValues) { if (!roofTextureIndex.Contains(textureIndex)) { BuildrTexture bTexture = data.textures[textureIndex]; Vector2 largestSubmeshPlaneSize = new Vector2(1, 1); Vector2 minWorldUvSize = dynMeshRoof.MinWorldUvSize(textureIndex); Vector2 maxWorldUvSize = dynMeshRoof.MaxWorldUvSize(textureIndex); largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x; largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y; int roofTextureWidth = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER); int roofTextureHeight = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER); Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight); packedTexturePositions.Add(newRoofTexutureRect); roofTextures.Add(bTexture); roofTextureIndex.Add(textureIndex); } } } //run a custom packer to define their postions textureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING); //determine the resize scale and apply that to the rects packedScale = 1; int numberOfRects = packedTexturePositions.Count; if (textureWidth > MAXIMUM_TEXTURESIZE) { packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth; for (int i = 0; i < numberOfRects; i++) { Rect thisRect = packedTexturePositions[i]; thisRect.x *= packedScale; thisRect.y *= packedScale; thisRect.width *= packedScale; thisRect.height *= packedScale; packedTexturePositions[i] = thisRect; //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]); } textureWidth = Mathf.RoundToInt(packedScale * textureWidth); } else { textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two } //Debug.Log("Texture Width "+textureWidth); //TODO: maybe restrict the resize to a power of two? LogTimer("Packed Rect Generated"); textureSize = textureWidth * textureWidth; colourArray = new Color32[textureSize]; //TestRectColours();//this test paints all the facades with rainbow colours - real pretty BuildTextures(); LogTimer("texture created"); Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true); packedTexture.filterMode = FilterMode.Bilinear; packedTexture.SetPixels32(colourArray); packedTexture.Apply(true, false); LogTimer("apply"); if (data.LODTextureAtlas != null) { Object.DestroyImmediate(data.LODTextureAtlas); } data.LODTextureAtlas = packedTexture; data.LODTextureAtlas.name = "Low Detail Texture"; //build the model with new uvs if (data.drawUnderside) { for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; Vector3[] newEndVerts = new Vector3[numberOfVolumePoints]; Vector2[] newEndUVs = new Vector2[numberOfVolumePoints]; for (int i = 0; i < numberOfVolumePoints; i++) { newEndVerts[i] = plan.points[volume.points[i]].vector3; newEndUVs[i] = Vector2.zero; } List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s)); tris.Reverse(); mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0); } } LogTimer("Floor"); //Build facades 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 = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; 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; Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight); Vector3 wallHeight = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart; p0 += floorHeightStart; p1 += floorHeightStart; Vector3 w0 = p0; Vector3 w1 = p1; Vector3 w2 = w0 + wallHeight; Vector3 w3 = w1 + wallHeight; Rect facadeRect = packedTexturePositions[facadeIndex]; float imageSize = textureWidth; Vector2 uvMin = new Vector2(facadeRect.xMin / imageSize, facadeRect.yMin / imageSize); Vector2 uvMax = new Vector2(facadeRect.xMax / imageSize, facadeRect.yMax / imageSize); mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0); facadeIndex++; } } LogTimer("Facades"); //ROOF Textures int roofRectBase = numberOfFacades; List <Rect> newAtlasRects = new List <Rect>(); for (int i = roofRectBase; i < packedTexturePositions.Count; i++) { Rect uvRect = new Rect();//generate a UV based rectangle off the packed one uvRect.x = packedTexturePositions[i].x / textureWidth; uvRect.y = packedTexturePositions[i].y / textureWidth; uvRect.width = packedTexturePositions[i].width / textureWidth; uvRect.height = packedTexturePositions[i].height / textureWidth; newAtlasRects.Add(uvRect); } dynMeshRoof.Atlas(roofTextureIndex.ToArray(), newAtlasRects.ToArray(), data.textures.ToArray()); //Add the atlased mesh data to the main model data at submesh 0 mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0); LogTimer("Roof B"); data = null; mesh = null; textures = null; //atlasRects = null; LogTimer("Done"); System.GC.Collect(); }
private static void Mansard(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfVolumePoints = volume.points.Count; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); //add top base of the flat roof Vector3[] topVerts = new Vector3[numberOfVolumePoints]; Vector2[] topUVs = new Vector2[numberOfVolumePoints]; int topTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floorB); BuildrTexture texture = textures[topTextureID]; for (int l = 0; l < numberOfVolumePoints; l++) { int indexA, indexB, indexA0, indexB0; Vector3 p0, p1, p00, p10; indexA = l; indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0; indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1; indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints; p0 = area.points[volume.points[indexA]].vector3; p1 = area.points[volume.points[indexB]].vector3; p00 = area.points[volume.points[indexA0]].vector3; p10 = area.points[volume.points[indexB0]].vector3; float facadeWidth = Vector3.Distance(p0, p1); Vector3 facadeDirection = (p1 - p0).normalized; Vector3 facadeDirectionLeft = (p0 - p00).normalized; Vector3 facadeDirectionRight = (p10 - p1).normalized; Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up); Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up); Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up); float roofHeight = design.height; float baseDepth = design.floorDepth; float cornerLeftRad = Vector3.Angle(facadeDirection, -facadeDirectionLeft) * Mathf.Deg2Rad / 2; float cornerRightRad = Vector3.Angle(-facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad / 2; float cornerDepthLeft = baseDepth / Mathf.Sin(cornerLeftRad); float cornerDepthRight = baseDepth / Mathf.Sin(cornerRightRad); float topDepth = design.depth; float cornerTopDepthLeft = topDepth / Mathf.Sin(cornerLeftRad); float cornerTopDepthRight = topDepth / Mathf.Sin(cornerRightRad); Vector3 pr = facadeDirection * facadeWidth; Vector3 leftDir = (facadeNormal + facadeNormalLeft).normalized; Vector3 rightDir = (facadeNormal + facadeNormalRight).normalized; p0 += volumeFloorHeight; p1 += volumeFloorHeight; Vector3 w0, w1, w2, w3, w4, w5; w0 = p0; w1 = p0 + pr; w2 = w0 + leftDir * cornerDepthLeft; w3 = w1 + rightDir * cornerDepthRight; w4 = w2 + leftDir * cornerTopDepthLeft + Vector3.up * roofHeight; w5 = w3 + rightDir * cornerTopDepthRight + Vector3.up * roofHeight; Vector3[] verts = new Vector3[6] { w0, w1, w2, w3, w4, w5 }; // List<Vector2> uvs = new List<Vector2>(); Vector2[] uvsFloor = BuildrProjectUVs.Project(new Vector3[4] { w0, w1, w2, w3 }, Vector2.zero, facadeNormal); if(baseDepth == 0) uvsFloor[3].x = facadeWidth; Vector2[] uvsMansard = BuildrProjectUVs.Project(new Vector3[3] { w2, w4, w5 }, uvsFloor[2], facadeNormal); Vector3[] vertsA = new Vector3[4] { verts[0], verts[1], verts[2], verts[3] }; Vector2[] uvsA = new Vector2[4] { uvsFloor[0], uvsFloor[1], uvsFloor[2], uvsFloor[3] }; int[] trisA = new int[6] { 1, 0, 2, 1, 2, 3 }; int subMeshA = design.GetTexture(BuildrRoofDesign.textureNames.floor); mesh.AddData(vertsA, uvsA, trisA, subMeshA); Vector3[] vertsB = new Vector3[4] { verts[2], verts[3], verts[4], verts[5] }; Vector2[] uvsB = new Vector2[4] { uvsFloor[2], uvsFloor[3], uvsMansard[1], uvsMansard[2] }; int[] trisB = new int[6] { 0, 2, 1, 1, 2, 3 }; int subMeshB = design.GetTexture(BuildrRoofDesign.textureNames.tiles); mesh.AddData(vertsB, uvsB, trisB, subMeshB); //modify point for the top geometry Vector2z point = area.points[volume.points[l]]; topVerts[l] = point.vector3 + volumeFloorHeight + Vector3.up * roofHeight + leftDir * (cornerDepthLeft + cornerTopDepthLeft); topUVs[l] = new Vector2(topVerts[l].x / texture.textureUnitSize.x, topVerts[l].z / texture.textureUnitSize.y); } Vector2z[] topVertV2z = new Vector2z[topVerts.Length]; for (int i = 0; i < topVerts.Length; i++) topVertV2z[i] = new Vector2z(topVerts[i]); int[] topTris = EarClipper.Triangulate(topVertV2z); AddData(topVerts, topUVs, topTris, topTextureID);//top }