示例#1
0
    void Awake()
    {
        data = gameObject.AddComponent<BuildrData>();
        data.Init();
        constraints = ScriptableObject.CreateInstance<BuildrRuntimeConstraints>();

    }
    public static void Generate(BuildrData data)
    {
        BuildrGenerateConstraints constraints = data.generatorConstraints;

        uint seed = (uint)(constraints.useSeed ? constraints.seed : Random.Range(0, int.MaxValue));
        constraints.seed = (int)seed;//reassign value incase it's changed
        constraints.rgen = new RandomGen(seed);
        RandomGen rgen = constraints.rgen;

        data.ResetData(constraints.constrainPlanByPlan);

        if (!constraints.constrainPlanByPlan)
            GenerateFloorPlan(data);
        else
            data.plan = constraints.plan;

        data.floorHeight = rgen.OutputRange(constraints.minimumFloorHeight, constraints.maximumFloorHeight);
        float minBuildingSize = (constraints.constrainHeight) ? constraints.minimumHeight : BuildrGenerateConstraints.MINIMUM_BUILDING_HEIGHT;
        float maxBuildingSize = (constraints.constrainHeight) ? constraints.maximumHeight : BuildrGenerateConstraints.MAXIMUM_BUILDING_HEIGHT;
        foreach(BuildrVolume volume in data.plan.volumes)
        {
            volume.height = rgen.OutputRange(minBuildingSize, maxBuildingSize);
            volume.numberOfFloors = Mathf.FloorToInt(volume.height / data.floorHeight);
        }

        //texture generation
        GetTextures(data);

        //facade generation
        GenerateFacades(data);

        //roof generation
        GenerateRoof(data);
    }
示例#3
0
    private static void GenerateFloorPlan(BuildrData data)
    {
        BuildrGenerateConstraints constraints = data.generatorConstraints;
        RandomGen rgen = constraints.rgen;

        BuildrPlan      plan            = ScriptableObject.CreateInstance <BuildrPlan>();
        List <Vector2z> bounds          = new List <Vector2z>();
        Rect            floorplanBounds = new Rect(-15, -15, 30, 30);

        if (constraints.constrainPlanByArea)
        {
            floorplanBounds = constraints.area;
        }
        bounds.Add(new Vector2z(rgen.OutputRange(-5, floorplanBounds.xMin), rgen.OutputRange(-5, floorplanBounds.yMin)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, floorplanBounds.xMax), rgen.OutputRange(-5, floorplanBounds.yMin)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, floorplanBounds.xMax), rgen.OutputRange(5, floorplanBounds.yMax)));
        bounds.Add(new Vector2z(rgen.OutputRange(-5, floorplanBounds.xMin), rgen.OutputRange(5, floorplanBounds.yMax)));

        if (rgen.output < 0.25f)//should we split the volume?
        {
            float ratio = rgen.OutputRange(0.25f, 0.75f);
            bounds.Insert(1, Vector2z.Lerp(bounds[0], bounds[1], ratio));
            bounds.Insert(4, Vector2z.Lerp(bounds[3], bounds[4], ratio));

            plan.AddVolume(new [] { bounds[0], bounds[1], bounds[4], bounds[5] });
            plan.AddVolume(1, 2, new [] { bounds[2], bounds[3] });
        }
        else
        {
            plan.AddVolume(bounds.ToArray());
        }

        data.plan = plan;
    }
    /// <summary>
    /// generate an array of gameobjects that contain all the generated detail meshes - ready to display in a scene
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public static GameObject[] Render(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data)
    {
        List<GameObject> detailGameobjects = new List<GameObject>();
        int numberOfDetails = data.details.Count;

        if (numberOfDetails == 0)
            return detailGameobjects.ToArray();

        BuildrDetailExportObject exportObject = Build(mesh, data);


        int numberOfMeshes = exportObject.detailMeshes.Length;
        if (numberOfMeshes == 0)
            return detailGameobjects.ToArray();

        if (detailMat == null)
            detailMat = new Material(Shader.Find("Diffuse"));
       
        detailMat.mainTexture = detailtexture;
        for (int i = 0; i < numberOfMeshes; i++)
        {
            GameObject details = new GameObject("details " + i);
            details.AddComponent<MeshFilter>().mesh = exportObject.detailMeshes[i];
            details.AddComponent<MeshRenderer>().sharedMaterial = detailMat;
            detailGameobjects.Add(details);
        }
        //        Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec");
        return detailGameobjects.ToArray();
    }
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
        switch(_data.generateCollider)
        {
                case BuildrData.ColliderGenerationModes.None:
                return;
//                break;

                case BuildrData.ColliderGenerationModes.Simple:
                BuildSimple(_mesh,_data);
                break;

                case BuildrData.ColliderGenerationModes.Complex:
                BuildrBuilding.Build(_mesh,_data);
                BuildrRoof.Build(_mesh, _data);
                int numberOfVolumes = _data.plan.numberOfVolumes;
                for(int v = 0; v < numberOfVolumes; v++)
                {
                    BuildrInteriors.Build(_mesh,_data,v);
                    BuildrStairs.Build(_mesh,_data,v,BuildrStairs.StairModes.Flat,false);
                }
                _mesh.CollapseSubmeshes();
                break;
        }
    }
示例#6
0
    private static void ImportFacades(XmlDocument xml, BuildrData data)
    {
        foreach(XmlNode node in xml.SelectNodes("buildr/facades/facade"))
        {
            BuildrFacadeDesign facadeDesign = new BuildrFacadeDesign();
            data.facades.Add(facadeDesign);

            facadeDesign.name = node["name"].FirstChild.Value;
            facadeDesign.hasWindows = node["hasWindows"].FirstChild.Value == valueTrue;
            facadeDesign.type = (BuildrFacadeDesign.types)System.Enum.Parse(typeof(BuildrFacadeDesign.types), (string)node["type"].FirstChild.Value);

            facadeDesign.simpleBay.name = node["simpleBayName"].FirstChild.Value;
            facadeDesign.simpleBay.openingWidth = float.Parse(node["simpleBayOpeningWidth"].FirstChild.Value);
            facadeDesign.simpleBay.openingHeight = float.Parse(node["simpleBayOpeningHeight"].FirstChild.Value);
            facadeDesign.simpleBay.minimumBayWidth = float.Parse(node["simpleBayMinimumBayWidth"].FirstChild.Value);
            facadeDesign.simpleBay.openingWidthRatio = float.Parse(node["simpleBayOpeningWidthRatio"].FirstChild.Value);
            facadeDesign.simpleBay.openingHeightRatio = float.Parse(node["simpleBayOpeningHeightRatio"].FirstChild.Value);
            facadeDesign.simpleBay.openingDepth = float.Parse(node["simpleBayOpeningDepth"].FirstChild.Value);
            facadeDesign.simpleBay.columnDepth = float.Parse(node["simpleBayColumnDepth"].FirstChild.Value);
            facadeDesign.simpleBay.rowDepth = float.Parse(node["simpleBayRowDepth"].FirstChild.Value);
            facadeDesign.simpleBay.crossDepth = float.Parse(node["simpleBayCrossDepth"].FirstChild.Value);

            for(int i = 0; i < 8; i++)
            {
                facadeDesign.simpleBay.textureValues[i] = int.Parse(node.SelectNodes("simpleBayTextures/texture")[i].FirstChild.Value);
                facadeDesign.simpleBay.flipValues[i] = node.SelectNodes("simpleBayflipvalues/flipvalue")[i].FirstChild.Value == valueTrue;
            }

            foreach(XmlNode baynode in node.SelectNodes("bays/bayid"))
            {
                facadeDesign.bayPattern.Add(int.Parse(baynode.FirstChild.Value));
            }
        }
    }
示例#7
0
    private static void ImportBays(XmlDocument xml, BuildrData data)
    {
        foreach (XmlNode node in xml.SelectNodes("buildr/bays/bay"))
        {
            BuildrBay bay = new BuildrBay("");
            data.bays.Add(bay);

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

            for (int i = 0; i < 8; i++)
            {
                bay.textureValues[i] = int.Parse(node.SelectNodes("bayTextures/texture")[i].FirstChild.Value);
                bay.flipValues[i] = node.SelectNodes("bayflipvalues/flipvalue")[i].FirstChild.Value == valueTrue;
            }
        }
    }
示例#8
0
    private static void ExportCollider(BuildrData data)
    {
        DynamicMeshGenericMultiMaterialMesh COL_MESH = new DynamicMeshGenericMultiMaterialMesh();

        COL_MESH.subMeshCount = data.textures.Count;
        BuildrBuildingCollider.Build(COL_MESH, data);
//        COL_MESH.CollapseSubmeshes();
        COL_MESH.Build(false);

        ExportMaterial[] exportTextures = new ExportMaterial[1];
        ExportMaterial   newTexture     = new ExportMaterial();

        newTexture.name      = "blank";
        newTexture.filepath  = "";
        newTexture.generated = true;
        exportTextures[0]    = newTexture;

        int numberOfColliderMeshes = COL_MESH.meshCount;

        for (int i = 0; i < numberOfColliderMeshes; i++)
        {
            MeshUtility.Optimize(COL_MESH[i].mesh);
            string ColliderSuffixIndex = ((numberOfColliderMeshes > 1) ? "_" + i : "");
            string ColliderFileName    = data.exportFilename + COLLIDER_SUFFIX + ColliderSuffixIndex;
            string ColliderFolder      = ROOT_FOLDER + data.exportFilename + "/";
            Export(ColliderFileName, ColliderFolder, data, COL_MESH[i].mesh, exportTextures);
        }
    }
示例#9
0
    private static void ImportDetails(XmlDocument xml, BuildrData data)
    {
        foreach (XmlNode node in xml.SelectNodes("buildr/details/detail"))
        {
            BuildrDetail detail = new BuildrDetail("");
            data.details.Add(detail);

            detail.name = node["name"].FirstChild.Value;
            detail.mesh = (Mesh)AssetDatabase.LoadAssetAtPath(node["mesh"].FirstChild.Value, typeof(Mesh));
            detail.material.mainTexture = (Texture2D)AssetDatabase.LoadAssetAtPath(node["texture"].FirstChild.Value, typeof(Texture2D));
            Vector2 faceUV = new Vector2();
            faceUV.x = float.Parse(node["faceuvx"].FirstChild.Value);
            faceUV.y = float.Parse(node["faceuvy"].FirstChild.Value);
            detail.faceUv = faceUV;
            detail.faceHeight = float.Parse(node["faceheight"].FirstChild.Value);
            Vector3 scale = new Vector3();
            scale.x = float.Parse(node["scalex"].FirstChild.Value);
            scale.y = float.Parse(node["scaley"].FirstChild.Value);
            scale.z = float.Parse(node["scalez"].FirstChild.Value);
            detail.scale = scale;
            detail.orientation = (BuildrDetail.Orientations)System.Enum.Parse(typeof(BuildrDetail.Orientations), node["orientation"].FirstChild.Value);
            Vector3 userRotation = new Vector3();
            userRotation.x = float.Parse(node["userRotationx"].FirstChild.Value);
            userRotation.y = float.Parse(node["userRotationy"].FirstChild.Value);
            userRotation.z = float.Parse(node["userRotationz"].FirstChild.Value);
            detail.userRotation = userRotation;
            detail.face = int.Parse(node["face"].FirstChild.Value);
            detail.type = (BuildrDetail.Types)System.Enum.Parse(typeof(BuildrDetail.Types), node["type"].FirstChild.Value);
        }
    }
示例#10
0
 /// <summary>
 /// Checks the Max UV values used in this model for each texture.
 /// </summary>
 /// <param name='data'>
 /// BuildR Data.
 /// </param>
 public void CheckMaxTextureUVs(BuildrData data)
 {
     foreach (DynamicMeshGenericMultiMaterial mesh in _meshes)
     {
         mesh.CheckMaxTextureUVs(data);
     }
 }
示例#11
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
        switch (_data.generateCollider)
        {
        case BuildrData.ColliderGenerationModes.None:
            return;

//                break;

        case BuildrData.ColliderGenerationModes.Simple:
            BuildSimple(_mesh, _data);
            break;

        case BuildrData.ColliderGenerationModes.Complex:
            BuildrBuilding.Build(_mesh, _data);
            BuildrRoof.Build(_mesh, _data);
            int numberOfVolumes = _data.plan.numberOfVolumes;
            for (int v = 0; v < numberOfVolumes; v++)
            {
                BuildrInteriors.Build(_mesh, _data, v);
                BuildrStairs.Build(_mesh, _data, v, BuildrStairs.StairModes.Flat, false);
            }
            _mesh.CollapseSubmeshes();
            break;
        }
    }
示例#12
0
    private static void GenerateFloorPlan(BuildrData data)
    {
        RandomGen rgen = constraints.rgen;

        BuildrPlan      plan   = ScriptableObject.CreateInstance <BuildrPlan>();
        List <Vector2z> bounds = new List <Vector2z>();

        bounds.Add(new Vector2z(rgen.OutputRange(-5, -15), rgen.OutputRange(-5, -15)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, 15), rgen.OutputRange(-5, -15)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, 15), rgen.OutputRange(5, 15)));
        bounds.Add(new Vector2z(rgen.OutputRange(-5, -15), rgen.OutputRange(5, 15)));

        if (rgen.output < 0.25f)//should we split the volume?
        {
            float ratio = rgen.OutputRange(0.25f, 0.75f);
            bounds.Insert(1, Vector2z.Lerp(bounds[0], bounds[1], ratio));
            bounds.Insert(4, Vector2z.Lerp(bounds[3], bounds[4], ratio));

            plan.AddVolume(new [] { bounds[0], bounds[1], bounds[4], bounds[5] });
            plan.AddVolume(1, 2, new [] { bounds[2], bounds[3] });
        }
        else
        {
            plan.AddVolume(bounds.ToArray());
        }

        data.plan = plan;
    }
示例#13
0
 public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
 {
     int numberOfFacades = _data.plan.numberOfFacades;
     Rect[] dummyUVConstraints = new Rect[numberOfFacades];
     for (int i = 0; i < numberOfFacades; i++)
         dummyUVConstraints[i] = new Rect(0,0,1,1);
     Build(_mesh, _data, dummyUVConstraints);
 }
 public static void RefreshTextures(BuildrData data)
 {
     data.textures.Clear();
     BuildrGenerateConstraints constraints = data.generatorConstraints;
     uint seed = (uint)(constraints.useSeed ? constraints.seed : Random.Range(0, int.MaxValue));
     constraints.rgen = new RandomGen(seed);
     GetTextures(data);
 }
示例#15
0
    public static void RefreshTextures(BuildrData data)
    {
        data.textures.Clear();
        BuildrGenerateConstraints constraints = data.generatorConstraints;
        uint seed = (uint)(constraints.useSeed ? constraints.seed : Random.Range(0, int.MaxValue));

        constraints.rgen = new RandomGen(seed);
        GetTextures(data);
    }
示例#16
0
 public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
 {
     if (GUI.changed)
     {
         EditorUtility.SetDirty(editMode);
         EditorUtility.SetDirty(data);
         editMode.UpdateRender();
     }
 }
示例#17
0
    private static int[] ExportStairwells(BuildrData data)
    {
        int numberOfVolumes = data.plan.numberOfVolumes;

        int[] returnNumberOfMeshes = new int[numberOfVolumes];

        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = data.plan.volumes[v];

            int numberOfUnpackedTextures         = data.textures.Count;
            List <ExportMaterial> exportTextures = new List <ExportMaterial>();

            if (!volume.generateStairs)
            {
                continue;
            }
            DynamicMeshGenericMultiMaterialMesh INT_STAIRWELL = new DynamicMeshGenericMultiMaterialMesh();
            INT_STAIRWELL.subMeshCount = data.textures.Count;
            BuildrStairs.Build(INT_STAIRWELL, data, v, BuildrStairs.StairModes.Stepped, true);
            INT_STAIRWELL.Build(data.includeTangents);

            List <int> unusedStairTextures = INT_STAIRWELL.unusedSubmeshes;
            numberOfUnpackedTextures = data.textures.Count;
            for (int t = 0; t < numberOfUnpackedTextures; t++)
            {
                if (unusedStairTextures.Contains(t))
                {
                    continue;//skip, unused
                }
                ExportMaterial newTexture = new ExportMaterial();
                newTexture.name      = data.textures[t].name;
                newTexture.material  = data.textures[t].material;
                newTexture.generated = false;
                newTexture.filepath  = data.textures[t].filePath;
                exportTextures.Add(newTexture);
            }

            int numberOfStairMeshes = INT_STAIRWELL.meshCount;
            for (int i = 0; i < numberOfStairMeshes; i++)
            {
                MeshUtility.Optimize(INT_STAIRWELL[i].mesh);
                string VolumeSuffix      = ((numberOfVolumes > 1) ? "_" + v : "");
                string DetailSuffixIndex = ((numberOfStairMeshes > 1) ? "_" + i : "");
                string DetailFileName    = data.exportFilename + STAIR_SUFFIX + VolumeSuffix + DetailSuffixIndex;
                string DetailFolder      = ROOT_FOLDER + data.exportFilename + "/";
                Export(DetailFileName, DetailFolder, data, INT_STAIRWELL[i].mesh, exportTextures.ToArray());
            }

            returnNumberOfMeshes[v] = numberOfStairMeshes;
        }

        return(returnNumberOfMeshes);
    }
示例#18
0
    public static void ImportFacades(string XMLPath, BuildrData data)
    {
        Debug.Log("Import Facades " + XMLPath);
        XmlDocument xml = new XmlDocument();
        using (StreamReader sr = new StreamReader(XMLPath))
        {
            xml.LoadXml(sr.ReadToEnd());
        }

        data.facades.Clear();
        ImportFacades(xml, data);
    }
    public static void ImportFacades(string XMLPath, BuildrData data)
    {
        Debug.Log("Import Facades " + XMLPath);
        XmlDocument xml = new XmlDocument();
        using (StreamReader sr = new StreamReader(XMLPath))
        {
            xml.LoadXml(sr.ReadToEnd());
        }

        data.facades.Clear();
        ImportFacades(xml, data);
    }
示例#20
0
    public static void InspectorGUI(BuildrEditMode _editMode, BuildrData _data)
    {
        editMode    = _editMode;
        data        = _data;
        constraints = data.generatorConstraints;

        EditModes newmode = (EditModes)EditorGUILayout.EnumPopup(mode);

        if (newmode != mode)
        {
            mode = newmode;
            switch (mode)
            {
            case EditModes.general:
                editMode.stage = BuildrEditMode.stages.building;
                break;

            case EditModes.floorplan:
                editMode.stage = BuildrEditMode.stages.floorplan;
                editMode.SetMode(BuildrEditMode.modes.floorplan);
                break;
            }
        }

        switch (mode)
        {
        case EditModes.general:
            GeneralOptionsInspector();
            break;

        case EditModes.floorplan:
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Constrain Building Generation to Floorplan", GUILayout.Width(280));
            constraints.constrainPlanByPlan = EditorGUILayout.Toggle(constraints.constrainPlanByPlan);
            EditorGUILayout.EndHorizontal();
            EditorGUI.BeginDisabledGroup(!constraints.constrainPlanByPlan);
            BuildrEditModeFloorplan.InspectorGUI(editMode, _data.plan);
            EditorGUI.EndDisabledGroup();

            if (data.plan != null)
            {
                constraints.plan = data.plan.Duplicate();
            }
            break;
        }

        if (GUI.changed)
        {
            EditorUtility.SetDirty(_editMode);
            EditorUtility.SetDirty(_data);
            _editMode.UpdateRender();
        }
    }
示例#21
0
    private static void Export(string filename, string folder, BuildrData data, Mesh exportMesh, ExportMaterial[] exportTextures)
    {
        switch (data.filetype)
        {
        case BuildrData.filetypes.obj:
            OBJExporter.Export(folder, filename, exportMesh, exportTextures, data.copyTexturesIntoExportFolder);
            break;

        case BuildrData.filetypes.fbx:
            FBXExporter.Export(folder, filename, exportMesh, exportTextures, data.copyTexturesIntoExportFolder);
            break;
        }
    }
示例#22
0
    private static void ImportVolumes(XmlDocument xml, BuildrData data)
    {
        foreach(XmlNode node in xml.SelectNodes("buildr/plan/volumes/volume"))
        {
            BuildrVolume volume = ScriptableObject.CreateInstance<BuildrVolume>();
            BuildrVolumeStyles styles = ScriptableObject.CreateInstance<BuildrVolumeStyles>();
            data.plan.volumes.Add(volume);

            foreach(XmlNode pointnode in node.SelectNodes("points/point"))
            {
                volume.points.Add(int.Parse(pointnode.FirstChild.Value));
            }
            foreach(XmlNode pointnode in node.SelectNodes("facades/render"))
            {
                volume.renderFacade.Add(pointnode.FirstChild.Value == valueTrue);
            }
            volume.height = float.Parse(node["height"].FirstChild.Value);
            volume.numberOfFloors = int.Parse(node["numberoffloors"].FirstChild.Value);
            volume.roofDesignID = int.Parse(node["roofdesignid"].FirstChild.Value);

            foreach(XmlNode stylenode in node.SelectNodes("styles/style"))
            {
                int styleID = int.Parse(stylenode["styleid"].FirstChild.Value);
                int facadeID = int.Parse(stylenode["facadeid"].FirstChild.Value);
                int floors = int.Parse(stylenode["floors"].FirstChild.Value);
                styles.AddStyle(styleID, facadeID, floors);
            }
            volume.styles = styles;


            volume.generateStairs = bool.Parse(node["generateStairs"].FirstChild.Value);
            volume.staircaseWidth = float.Parse(node["staircaseWidth"].FirstChild.Value);
            volume.stepHeight = float.Parse(node["stepHeight"].FirstChild.Value);
            volume.stairwellCeilingTexture = int.Parse(node["stairwellCeilingTexture"].FirstChild.Value);
            volume.stairwellFloorTexture = int.Parse(node["stairwellFloorTexture"].FirstChild.Value);
            volume.stairwellStepTexture = int.Parse(node["stairwellStepTexture"].FirstChild.Value);
            volume.stairwellWallTexture = int.Parse(node["stairwellWallTexture"].FirstChild.Value);
            volume.numberOfBasementFloors = int.Parse(node["numberOfBasementFloors"].FirstChild.Value);

            int itemCount = 0;
            foreach (XmlNode basementNode in node.SelectNodes("basementtextures/basementfloortextures"))
            {
                volume.FloorTexture(itemCount, int.Parse(basementNode["FloorTexture"].FirstChild.Value));
                volume.WallTexture(itemCount, int.Parse(basementNode["WallTexture"].FirstChild.Value));
                volume.CeilingTexture(itemCount, int.Parse(basementNode["CeilingTexture"].FirstChild.Value));
                itemCount++;
            }
        }
    }
示例#23
0
    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));
        }
    }
示例#24
0
    void OnEnable()
    {
        if (target != null)
        {
            _editMode = (BuildrEditMode)target;
            _data     = _editMode.data;
        }


        bool editing = (_data != null) ? _data.editing : true;

        if (!editing)
        {
            BuildrGenerateModeEditor.OnEnable();
        }
    }
示例#25
0
    public static void Generate(BuildrData data, BuildrRuntimeConstraints _constraints)
    {
        constraints = _constraints;
        uint seed = (uint)(constraints.useSeed ? constraints.seed : Random.Range(0, int.MaxValue));

        constraints.seed = (int)seed;//reassign value incase it's changed
        constraints.rgen = new RandomGen(seed);
        RandomGen rgen = constraints.rgen;

        //Debug.Log("Generate Seed "+seed);

        data.ResetData(constraints.constrainPlanByPlan);

        if (!constraints.constrainPlanByPlan)
        {
            GenerateFloorPlan(data);
        }
        else
        {
            data.plan = constraints.plan;
        }

        data.floorHeight = rgen.OutputRange(constraints.minimumFloorHeight, constraints.maximumFloorHeight);
        float minBuildingSize = (constraints.constrainHeight) ? constraints.minimumHeight : BuildrGenerateConstraints.MINIMUM_BUILDING_HEIGHT;
        float maxBuildingSize = (constraints.constrainHeight) ? constraints.maximumHeight : BuildrGenerateConstraints.MAXIMUM_BUILDING_HEIGHT;

        foreach (BuildrVolume volume in data.plan.volumes)
        {
            volume.height         = rgen.OutputRange(minBuildingSize, maxBuildingSize);
            volume.numberOfFloors = Mathf.FloorToInt(volume.height / data.floorHeight);
        }

        //texture generation
        GetTextures(data);

        //facade generation
        GenerateFacades(data);

        //roof generation
        GenerateRoof(data);

        //building generation

        //build/optimise
    }
    public static void ExportFacades(string filepath, BuildrData _data)
    {
        data = _data;
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("<?xml version='1.0' encoding='ISO-8859-15'?>");
        sb.AppendLine("<!-- Unity3D Asset Buildr XML Exporter http://buildr.jasperstocker.com -->");

        sb.AppendLine("<buildr version='" + data.versionNumber + "'>");
        sb.Append(ExportFacades());
        sb.AppendLine("</buildr>");

        using (StreamWriter sw = new StreamWriter(filepath))
        {
            sw.Write(sb.ToString());//write out contents of data to XML
        }

        data = null;
    }
示例#27
0
    private static void ExportLowLOD(BuildrData data)
    {
        DynamicMeshGenericMultiMaterialMesh dynLODMesh = new DynamicMeshGenericMultiMaterialMesh();

        dynLODMesh.subMeshCount = data.textures.Count;
        BuildrBuildingLowDetail2.Build(dynLODMesh, data);
        dynLODMesh.CollapseSubmeshes();
        EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.80f);
        dynLODMesh.Build(data.includeTangents);
        Mesh LODMesh = dynLODMesh[0].mesh;//TODO: support many meshes

        MeshUtility.Optimize(LODMesh);
        EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.90f);

        string textureName     = data.exportFilename + ATLASED_SUFFIX + LOD_SUFFIX;
        string textureFileName = textureName + ".png";
        string newDirectory    = ROOT_FOLDER + data.exportFilename;

        File.WriteAllBytes(newDirectory + "/" + textureFileName, data.LODTextureAtlas.EncodeToPNG());
        ExportMaterial[] exportTextures = new ExportMaterial[1];
        ExportMaterial   newTexture     = new ExportMaterial();

        newTexture.name      = textureName;
        newTexture.filepath  = textureFileName;
        newTexture.generated = true;
        exportTextures[0]    = newTexture;
        string LODFileName = data.exportFilename + LOD_SUFFIX;
        string LODFolder   = ROOT_FOLDER + data.exportFilename + "/";

        Export(LODFileName, LODFolder, data, LODMesh, exportTextures);


        if (data.placeIntoScene)
        {
            AssetDatabase.Refresh();//ensure the database is up to date...
            string     filePath = LODFolder + LODFileName + FILE_EXTENTION;
            GameObject newModel = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadMainAssetAtPath(filePath));
            newModel.transform.position = CURRENT_TRANSFORM.position;
            newModel.transform.rotation = CURRENT_TRANSFORM.rotation;
        }

        Texture2D.DestroyImmediate(data.textureAtlas);
        Texture2D.DestroyImmediate(data.LODTextureAtlas);
    }
示例#28
0
    //data should be already created, attached to the gameobject as a component and init run.
    public static void Import(string XMLPath, BuildrData data)
    {
        Debug.Log("Import " + XMLPath);
        XmlDocument xml = new XmlDocument();
        using(StreamReader sr = new StreamReader(XMLPath))
        {
            xml.LoadXml(sr.ReadToEnd());
        }

        float xmlVersionNumber = float.Parse(xml["buildr"].Attributes["version"].Value);

        if(xmlVersionNumber != BuildrVersion.NUMBER)
            Debug.Log("Version upgrade " + xmlVersionNumber + " > " + BuildrVersion.NUMBER);


        data.name = xml["buildr"]["buildingname"].FirstChild.Value;
        data.floorHeight = float.Parse(xml["buildr"]["floorheight"].FirstChild.Value);
        data.foundationHeight = float.Parse(xml["buildr"]["foundationHeight"].FirstChild.Value);
        data.drawUnderside = bool.Parse(xml["buildr"]["drawUnderside"].FirstChild.Value);
        data.generateCollider = (BuildrData.ColliderGenerationModes)System.Enum.Parse(typeof(BuildrData.ColliderGenerationModes), xml["buildr"]["generateCollider"].FirstChild.Value);
        data.renderInteriors = bool.Parse(xml["buildr"]["renderInteriors"].FirstChild.Value);
        data.interiorCeilingHeight = float.Parse(xml["buildr"]["interiorCeilingHeight"].FirstChild.Value);
        data.cullBays = bool.Parse(xml["buildr"]["cullBays"].FirstChild.Value);

        //volume points
        foreach(XmlNode node in xml.SelectNodes("buildr/plan/points/point"))
        {
            data.plan.points.Add(new Vector2z(node["x"].FirstChild.Value, node["z"].FirstChild.Value));
        }

        //volume cores
        foreach (XmlNode node in xml.SelectNodes("buildr/plan/cores/core"))
        {
            data.plan.cores.Add(new Rect(float.Parse(node["xMin"].FirstChild.Value), float.Parse(node["yMin"].FirstChild.Value), float.Parse(node["width"].FirstChild.Value), float.Parse(node["height"].FirstChild.Value)));
        }

        ImportVolumes(xml,data);
        ImportFacades(xml,data);
        ImportRoofs(xml,data);
        ImportTextures(xml,data);
        ImportBays(xml,data);
        ImportDetails(xml,data);
    }
示例#29
0
    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);
    }
示例#30
0
    public static void ExportRoofs(string filepath, BuildrData _data)
    {
        data = _data;
        StringBuilder sb = new StringBuilder();

        sb.AppendLine("<?xml version='1.0' encoding='ISO-8859-15'?>");
        sb.AppendLine("<!-- Unity3D Asset Buildr XML Exporter http://buildr.jasperstocker.com -->");

        sb.AppendLine("<buildr version='" + data.versionNumber + "'>");
        sb.Append(ExportRoofs());
        sb.AppendLine("</buildr>");

        using (StreamWriter sw = new StreamWriter(filepath))
        {
            sw.Write(sb.ToString());//write out contents of data to XML
        }

        data = null;
    }
    //data should be already created, attached to the gameobject as a component and init run.
    public static void Import(string XMLPath, BuildrData data)
    {
        Debug.Log("Import " + XMLPath);
        XmlDocument xml = new XmlDocument();
        using(StreamReader sr = new StreamReader(XMLPath))
        {
            xml.LoadXml(sr.ReadToEnd());
        }

        float xmlVersionNumber = float.Parse(xml["buildr"].Attributes["version"].Value);

        if(xmlVersionNumber != BuildrVersion.NUMBER)
            Debug.Log("Version upgrade " + xmlVersionNumber + " > " + BuildrVersion.NUMBER);

        data.name = xml["buildr"]["buildingname"].FirstChild.Value;
        data.floorHeight = float.Parse(xml["buildr"]["floorheight"].FirstChild.Value);
        data.foundationHeight = float.Parse(xml["buildr"]["foundationHeight"].FirstChild.Value);
        data.drawUnderside = bool.Parse(xml["buildr"]["drawUnderside"].FirstChild.Value);
        data.generateCollider = (BuildrData.ColliderGenerationModes)System.Enum.Parse(typeof(BuildrData.ColliderGenerationModes), xml["buildr"]["generateCollider"].FirstChild.Value);
        data.renderInteriors = bool.Parse(xml["buildr"]["renderInteriors"].FirstChild.Value);
        data.interiorCeilingHeight = float.Parse(xml["buildr"]["interiorCeilingHeight"].FirstChild.Value);
        data.cullBays = bool.Parse(xml["buildr"]["cullBays"].FirstChild.Value);

        //volume points
        foreach(XmlNode node in xml.SelectNodes("buildr/plan/points/point"))
        {
            data.plan.points.Add(new Vector2z(node["x"].FirstChild.Value, node["z"].FirstChild.Value));
        }

        //volume cores
        foreach (XmlNode node in xml.SelectNodes("buildr/plan/cores/core"))
        {
            data.plan.cores.Add(new Rect(float.Parse(node["xMin"].FirstChild.Value), float.Parse(node["yMin"].FirstChild.Value), float.Parse(node["width"].FirstChild.Value), float.Parse(node["height"].FirstChild.Value)));
        }

        ImportVolumes(xml,data);
        ImportFacades(xml,data);
        ImportRoofs(xml,data);
        ImportTextures(xml,data);
        ImportBays(xml,data);
        ImportDetails(xml,data);
    }
示例#32
0
    /// <summary>
    /// Checks the Max UV values used in this model for each texture.
    /// </summary>
    /// <param name='data'>
    /// BuildR Data.
    /// </param>
    public void CheckMaxTextureUVs(BuildrData data)
    {
        Vector2[] subMeshUVOffsets   = new Vector2[subMeshCount];
        int[]     subMeshIDs         = new List <int>(subTriangles.Keys).ToArray();
        int       numberOfSubmeshIDs = subMeshIDs.Length;

        for (int sm = 0; sm < numberOfSubmeshIDs; sm++)
        {
            int subMeshID = subMeshIDs[sm];
            if (subTriangles.ContainsKey(subMeshID))
            {
                int[] submeshIndices = subTriangles[subMeshID].ToArray();
                subMeshUVOffsets[sm] = Vector2.zero;
                foreach (int index in submeshIndices)
                {
                    if (uv[index].x < subMeshUVOffsets[sm].x)
                    {
                        subMeshUVOffsets[sm].x = uv[index].x;
                    }
                    if (uv[index].y < subMeshUVOffsets[sm].y)
                    {
                        subMeshUVOffsets[sm].y = uv[index].y;
                    }
                }

                List <int> UVsOffset = new List <int>();
                foreach (int uvindex in subTriangles[subMeshID])
                {
                    if (!UVsOffset.Contains(uvindex))
                    {
                        uv[uvindex] += -subMeshUVOffsets[sm];//offset the UV to ensure it isn't negative
                        UVsOffset.Add(uvindex);
                    }
                    data.textures[subMeshID].CheckMaxUV(uv[uvindex]);
                }
            }
            else
            {
                Debug.Log("Mesh does not contain key for texture " + data.textures[subMeshID].name);
            }
        }
    }
示例#33
0
    public static bool Export(string folder, string filename, BuildrData _data)
    {
        targetFolder = folder;
        targetName   = filename;
        data         = _data;

        if (folder.Contains(" "))
        {
            EditorUtility.DisplayDialog("Filename Error", "The filename can't contain spaces", "I'm sorry");
            return(false);
        }

        if (filename.Contains(" "))
        {
            EditorUtility.DisplayDialog("Filename Error", "The filename can't contain spaces", "I'm sorry");
            return(false);
        }

        //Export code
        StringBuilder sb = new StringBuilder();

        sb.AppendLine("<?xml version='1.0' encoding='ISO-8859-15'?>");
        sb.AppendLine("<!-- Unity3D Asset Buildr XML Exporter http://buildr.jasperstocker.com -->");

        sb.AppendLine("<buildr version='" + data.versionNumber + "'>");

        sb.Append(ExportData());

        //end
        sb.AppendLine("</buildr>");

        CreateTargetFolder();
        using (StreamWriter sw = new StreamWriter(targetFolder + "/" + targetName + ".xml"))
        {
            sw.Write(sb.ToString());//write out contents of data to XML
        }

        data = null;
        return(true);
    }
    public static bool Export(string folder, string filename, BuildrData _data)
    {
        targetFolder = folder;
        targetName = filename;
        data = _data;

        if (folder.Contains(" "))
        {
            EditorUtility.DisplayDialog("Filename Error", "The filename can't contain spaces", "I'm sorry");
            return false;
        }

        if (filename.Contains(" "))
        {
            EditorUtility.DisplayDialog("Filename Error", "The filename can't contain spaces", "I'm sorry");
            return false;
        }

        //Export code
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("<?xml version='1.0' encoding='ISO-8859-15'?>");
        sb.AppendLine("<!-- Unity3D Asset Buildr XML Exporter http://buildr.jasperstocker.com -->");

        sb.AppendLine("<buildr version='" + data.versionNumber + "'>");

        sb.Append(ExportData());

        //end
        sb.AppendLine("</buildr>");

        CreateTargetFolder();
        using (StreamWriter sw = new StreamWriter(targetFolder + "/" + targetName + ".xml"))
        {
            sw.Write(sb.ToString());//write out contents of data to XML
        }

        data = null;
        return true;
    }
示例#35
0
    private static void ImportRoofs(XmlDocument xml, BuildrData data)
    {
        foreach(XmlNode node in xml.SelectNodes("buildr/roofs/roof"))
        {
            BuildrRoofDesign roofDesign = new BuildrRoofDesign("");
            data.roofs.Add(roofDesign);

            roofDesign.name = node["name"].FirstChild.Value;
            roofDesign.style = (BuildrRoofDesign.styles)System.Enum.Parse(typeof(BuildrRoofDesign.styles), node["style"].FirstChild.Value);
            roofDesign.height = float.Parse(node["height"].FirstChild.Value);
            roofDesign.depth = float.Parse(node["depth"].FirstChild.Value);
            roofDesign.floorDepth = float.Parse(node["floorDepth"].FirstChild.Value);
            roofDesign.direction = int.Parse(node["direction"].FirstChild.Value);
            roofDesign.sawtoothTeeth = int.Parse(node["sawtoothTeeth"].FirstChild.Value);
            roofDesign.barrelSegments = int.Parse(node["barrelSegments"].FirstChild.Value);
            roofDesign.parapet = node["parapet"].FirstChild.Value == valueTrue;
            roofDesign.parapetStyle = (BuildrRoofDesign.parapetStyles)System.Enum.Parse(typeof(BuildrRoofDesign.parapetStyles), node["parapetStyle"].FirstChild.Value);
            roofDesign.parapetDesignWidth = float.Parse(node["parapetDesignWidth"].FirstChild.Value);
            roofDesign.parapetHeight = float.Parse(node["parapetHeight"].FirstChild.Value);
            roofDesign.parapetFrontDepth = float.Parse(node["parapetFrontDepth"].FirstChild.Value);
            roofDesign.parapetBackDepth = float.Parse(node["parapetBackDepth"].FirstChild.Value);
            roofDesign.hasDormers = node["hasDormers"].FirstChild.Value == valueTrue;
            roofDesign.dormerWidth = float.Parse(node["dormerWidth"].FirstChild.Value);
            roofDesign.dormerHeight = float.Parse(node["dormerHeight"].FirstChild.Value);
            roofDesign.dormerRoofHeight = float.Parse(node["dormerRoofHeight"].FirstChild.Value);
            roofDesign.minimumDormerSpacing = float.Parse(node["minimumDormerSpacing"].FirstChild.Value);
            roofDesign.dormerHeightRatio = float.Parse(node["dormerHeightRatio"].FirstChild.Value);


            for(int i = 0; i < 8; i++)
            {
                roofDesign.textureValues[i] = int.Parse(node.SelectNodes("textures/texture")[i].FirstChild.Value);
                roofDesign.flipValues[i] = node.SelectNodes("flipvalues/flipvalue")[i].FirstChild.Value == valueTrue;
            }
        }
    }
示例#36
0
    //returns the number of meshes
    private static int ExportDetails(BuildrData data)
    {
        DynamicMeshGenericMultiMaterialMesh DET_MESH     = new DynamicMeshGenericMultiMaterialMesh();
        BuildrDetailExportObject            exportObject = BuildrBuildingDetails.Build(DET_MESH, data);

        int numberOfMeshes = exportObject.detailMeshes.Length;

        if (numberOfMeshes == 0)
        {
            return(0);
        }

        string textureName     = data.exportFilename + ATLASED_SUFFIX + DETAIL_SUFFIX;
        string textureFileName = textureName + ".png";
        string newDirectory    = ROOT_FOLDER + data.exportFilename;

        File.WriteAllBytes(newDirectory + "/" + textureFileName, exportObject.texture.EncodeToPNG());
        ExportMaterial[] exportTextures = new ExportMaterial[1];
        ExportMaterial   newTexture     = new ExportMaterial();

        newTexture.name      = textureName;
        newTexture.filepath  = textureFileName;
        newTexture.generated = true;
        exportTextures[0]    = newTexture;
        for (int i = 0; i < numberOfMeshes; i++)
        {
            string DetailSuffixIndex = ((numberOfMeshes > 1) ? "_" + i : "");
            string DetailFileName    = data.exportFilename + DETAIL_SUFFIX + DetailSuffixIndex;
            string DetailFolder      = ROOT_FOLDER + data.exportFilename + "/";
            Export(DetailFileName, DetailFolder, data, exportObject.detailMeshes[i], exportTextures);
        }

        Texture2D.DestroyImmediate(exportObject.texture);

        return(numberOfMeshes);
    }
示例#37
0
    /// <summary>
    /// generate an array of gameobjects that contain all the generated detail meshes - ready to display in a scene
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public static GameObject[] Render(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data)
    {
        List <GameObject> detailGameobjects = new List <GameObject>();
        int numberOfDetails = data.details.Count;

        if (numberOfDetails == 0)
        {
            return(detailGameobjects.ToArray());
        }

        BuildrDetailExportObject exportObject = Build(mesh, data);


        int numberOfMeshes = exportObject.detailMeshes.Length;

        if (numberOfMeshes == 0)
        {
            return(detailGameobjects.ToArray());
        }

        if (detailMat == null)
        {
            detailMat = new Material(Shader.Find("Diffuse"));
        }

        detailMat.mainTexture = detailtexture;
        for (int i = 0; i < numberOfMeshes; i++)
        {
            GameObject details = new GameObject("details " + i);
            details.AddComponent <MeshFilter>().mesh             = exportObject.detailMeshes[i];
            details.AddComponent <MeshRenderer>().sharedMaterial = detailMat;
            detailGameobjects.Add(details);
        }
        //        Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec");
        return(detailGameobjects.ToArray());
    }
    /// <summary>
    /// Checks the Max UV values used in this model for each texture.
    /// </summary>
    /// <param name='data'>
    /// BuildR Data.
    /// </param>
    public void CheckMaxTextureUVs(BuildrData data)
    {
        Vector2[] subMeshUVOffsets = new Vector2[subMeshCount];
        int[] subMeshIDs = new List<int>(subTriangles.Keys).ToArray();
        int numberOfSubmeshIDs = subMeshIDs.Length;
        for (int sm = 0; sm < numberOfSubmeshIDs; sm++)
        {
            int subMeshID = subMeshIDs[sm];
            if (subTriangles.ContainsKey(subMeshID))
            {
                int[] submeshIndices = subTriangles[subMeshID].ToArray();
                subMeshUVOffsets[sm] = Vector2.zero;
                foreach (int index in submeshIndices)
                {
                    if (uv[index].x < subMeshUVOffsets[sm].x)
                        subMeshUVOffsets[sm].x = uv[index].x;
                    if (uv[index].y < subMeshUVOffsets[sm].y)
                        subMeshUVOffsets[sm].y = uv[index].y;
                }

                List<int> UVsOffset = new List<int>();
                foreach (int uvindex in subTriangles[subMeshID])
                {
                    if (!UVsOffset.Contains(uvindex))
                    {
                        uv[uvindex] += -subMeshUVOffsets[sm];//offset the UV to ensure it isn't negative
                        UVsOffset.Add(uvindex);
                    }
                    data.textures[subMeshID].CheckMaxUV(uv[uvindex]);
                }
            }
            else
            {
                Debug.Log("Mesh does not contain key for texture " + data.textures[subMeshID].name);
            }
        }
    }
    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();
    }
    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 SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
    {
        if(editMode.fullMesh==null)
            return;

        Rect HUDRect = new Rect(0,0,300,300);
        Handles.BeginGUI();
        GUILayout.BeginArea(HUDRect);

            EditorGUILayout.LabelField("Buildr");
            EditorGUILayout.LabelField("Vertices: "+editMode.fullMesh.vertexCount);
            EditorGUILayout.LabelField("Triangles "+editMode.fullMesh.triangleCount/3);

        GUILayout.EndArea();
        Handles.EndGUI();

        bool isLegal = !(data.plan.illegalPoints.Length > 0);
        if (isLegal)
            isLegal = editMode.transform.localScale == Vector3.one;

        if(isLegal)
            return;

        int numberOfFacades = data.facades.Count;
        int numberOfRoofs = data.roofs.Count;
        int numberOfTextures = data.textures.Count;

        if (numberOfFacades == 0 || numberOfRoofs == 0 || numberOfTextures == 0)
            return;

        Vector3 position = editMode.transform.position;

        BuildrPlan area = data.plan;
        int numberOfVolumes = area.numberOfVolumes;

        int facadeCounter = 0;
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = data.plan.volumes[s];
            int volumeSize = volume.Count;
            Vector3 floorCentre = Vector3.zero;
            Handles.color = Color.red;

            for (int p = 0; p < volumeSize; p++)
            {
                int point = volume.points[p];
                Vector3 pointPos = area.points[point].vector3;
                floorCentre += pointPos;

                List<Vector3> verts = new List<Vector3>();
                int indexB = (p < volumeSize - 1) ? p + 1 : 0;
                Vector3 volumeHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight);
                verts.Add(pointPos + position);
                verts.Add(area.points[volume.points[indexB]].vector3 + position);
                verts.Add(verts[1] + volumeHeight);
                verts.Add(verts[0] + volumeHeight);
                Handles.DrawSolidRectangleWithOutline(verts.ToArray(), new Color(1,0,0,0.2f), Color.red);
                Handles.DrawLine(verts[2], verts[3]);
                facadeCounter++;
            }
        }
    }
示例#42
0
    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();
    }
示例#43
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, bool ignoreParapets)
    {
        data = _data;
        mesh = _mesh;
        textures = data.textures.ToArray();
        BuildrPlan plan = data.plan;

        int numberOfVolumes = data.plan.numberOfVolumes;
        for (int s = 0; s < numberOfVolumes; s++)
        {

            BuildrVolume volume = plan.volumes[s];
            BuildrRoofDesign design = data.roofs[volume.roofDesignID];

            BuildrRoofDesign.styles style = design.style;
            if (volume.points.Count != 4)
                if (design.style == BuildrRoofDesign.styles.leanto || design.style == BuildrRoofDesign.styles.sawtooth || design.style == BuildrRoofDesign.styles.barrel)
                    style = BuildrRoofDesign.styles.flat;//ignore style and just do a flat roof

            if (volume.points.Count != 4 && design.style == BuildrRoofDesign.styles.gabled)
                style = BuildrRoofDesign.styles.hipped;//ignore style and just do a hipped roof

            switch (style)
            {
                case BuildrRoofDesign.styles.flat:
                    FlatRoof(volume, design);
                    break;
                case BuildrRoofDesign.styles.mansard:
                    Mansard(volume, design);
                    if (design.hasDormers)
                        Dormers(volume, design);
                    break;
                case BuildrRoofDesign.styles.gabled:
                    Gabled(volume, design);
                    break;
                case BuildrRoofDesign.styles.hipped:
                    Hipped(volume, design);
                    break;
                case BuildrRoofDesign.styles.leanto:
                    LeanTo(volume, design);
                    break;
                case BuildrRoofDesign.styles.sawtooth:
                    Sawtooth(volume, design);
                    break;
                case BuildrRoofDesign.styles.barrel:
                    Barrel(volume, design);
                    break;
                case BuildrRoofDesign.styles.steepled:
                    Steeple(volume, design);
                    break;
            }

            if (design.parapet && !ignoreParapets)
                Parapet(volume, design);

        }

        data = null;
        mesh = null;
        textures = null;
    }
    public static void InspectorGUI(BuildrEditMode editMode, BuildrData data)
    {
        if (data.plan==null || data.plan.numberOfVolumes == 0)
        {
            EditorGUILayout.HelpBox("There are no defined volumes, go to Floorplan and define one", MessageType.Error);
            return;
        }

        const int guiWidth = 400;
        const int textWidth = 348;
        const int toggleWidth = 25;
        const int helpWidth = 20;

        CURRENT_TRANSFORM = editMode.transform;
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Filename", GUILayout.Width(225));
        data.exportFilename = EditorGUILayout.TextField(data.exportFilename, GUILayout.Width(175));
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Filetype", GUILayout.Width(350));
        data.filetype = (BuildrData.filetypes)EditorGUILayout.EnumPopup(data.filetype, GUILayout.Width(50));
        switch (data.filetype)
        {
            case BuildrData.filetypes.obj:
                FILE_EXTENTION = ".obj";
                break;
            case BuildrData.filetypes.fbx:
                FILE_EXTENTION = ".fbx";
                break;
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Export Full Mesh", GUILayout.Width(textWidth));
        data.fullmesh = EditorGUILayout.Toggle(data.fullmesh, GUILayout.Width(toggleWidth));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Export Full Mesh";
            string helpBody = "Select this checkbox if you want your export the full detail model.";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Place Exported Model Into Scene", GUILayout.Width(textWidth));
        data.placeIntoScene = EditorGUILayout.Toggle(data.placeIntoScene, GUILayout.Width(toggleWidth));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Place Exported Model Into Scene";
            string helpBody = "Select this checkbox if you want your exported models to be copied into your scene." +
                "\nThese will be positioned correctly and will include colliders and LOD models if you opt to export them also.";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Copy Textures into Export Folder", GUILayout.Width(textWidth));
        data.copyTexturesIntoExportFolder = EditorGUILayout.Toggle(data.copyTexturesIntoExportFolder, GUILayout.Width(toggleWidth));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Copy Textures into Export Folder";
            string helpBody = "Check this box if you want to copy the textures you are using into the export folder." +
                "\nThis is useful if you plan to use the exported model elsewhere. Having the model and the textures in one folder will allow you to move this model with ease.";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Export Collider");
        data.generateCollider = (BuildrData.ColliderGenerationModes)EditorGUILayout.EnumPopup(data.generateCollider, GUILayout.Width(80));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Export Collider Mesh";
            string helpBody = "Check this box if you wish to generate a collider mesh for your model." +
                "\nThis will generate a mesh to be used with colliders.";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Export as Prefab", GUILayout.Width(textWidth));
        data.createPrefabOnExport = EditorGUILayout.Toggle(data.createPrefabOnExport, GUILayout.Width(toggleWidth));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Export as Prefab";
            string helpBody = "Select this if you wish to create a prefab of your model." +
                "\nThis is recommended if you're exporting a collider so they will get packaged together.";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Export a Low Detail Version", GUILayout.Width(textWidth));
        data.exportLowLOD = EditorGUILayout.Toggle(data.exportLowLOD, GUILayout.Width(toggleWidth));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - Export a Low Detail Version";
            string helpBody = "Check this box to export a simplified model of your building." +
                "\nIdeal to use as a low level of detail version of your model." +
                "\nGeometry will be significantly reduced." +
                "\nFacades will flat and exported as a single atlased texture" +
                "\nThe model will use 1 draw call and will have around 10% of the triangles and verticies";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Export with tangents", GUILayout.Width(textWidth));
        data.includeTangents = EditorGUILayout.Toggle(data.includeTangents, GUILayout.Width(toggleWidth));
        if (GUILayout.Button("?", GUILayout.Width(helpWidth)))
        {
            string helpTitle = "Help - with tangents";
            string helpBody = "Export the models with calculated tangents." +
                "\nSome shaders require tangents to be calculated on the model." +
                "\nUnity will do this automatically on all imported meshes so it's not neccessary here." +
                "/nBut you might want them if you're taking them to another program.";
            EditorUtility.DisplayDialog(helpTitle, helpBody, "close");
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.Space();

        bool unreadableTextures = false;
        bool nullTextures = false;
        string unreadableTextureList = "";
        foreach (BuildrTexture bTexture in data.textures)//check texture readablility
        {
            if(bTexture.type == BuildrTexture.Types.Substance)
                continue;//substances are preset in BuildrTexture class
            if (bTexture.texture != null)
            {
                string texturePath = AssetDatabase.GetAssetPath(bTexture.texture);
                TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath);
                if (!textureImporter.isReadable)
                {
                    unreadableTextures = true;
                    if (unreadableTextureList.Length > 0)
                        unreadableTextureList += ", ";
                    unreadableTextureList += "'" + bTexture.name + "'";
                }
            }
            else
            {
                nullTextures = true;
            }
        }

        if (unreadableTextures)
        {
            EditorGUILayout.HelpBox("Unreadable Texture Error." +
                "\nThe following textures you are useing are not readable." +
                "\n" + unreadableTextureList + "." +
                "\nPlease select the readable checkbox under advanced texture settings." +
                "\nOr move this texture to the BuildR texture folder and reimport.",
                MessageType.Error);
        }

        if (nullTextures)
        {
            EditorGUILayout.HelpBox("Null Texture Error" +
                "\nSome of the textures have not been set" +
                "\nEnsure you are not using null textures to proceed.",
                MessageType.Error);
        }

        bool usingSubstances = false;
        foreach(BuildrTexture bTexture in data.textures)
        {
            if(bTexture.type == BuildrTexture.Types.Substance)
            {
                usingSubstances = true;
                break;
            }
        }
        if (usingSubstances)
        {
            EditorGUILayout.HelpBox("Model uses Substance textures." +
                "\nExporting model to " + data.filetype + " will lose references to this texture and it will be rendered white.",
                MessageType.Warning);
        }

        EditorGUI.BeginDisabledGroup(unreadableTextures || nullTextures);

        if (GUILayout.Button("Export", GUILayout.Width(guiWidth), GUILayout.Height(40)))
        {
            ExportModel(data);
        }

        if (GUILayout.Button("Export Data to XML", GUILayout.Width(guiWidth)))
        {
            BuildrXMLExporter.Export(ROOT_FOLDER + data.exportFilename + "/", data.exportFilename, data);
            AssetDatabase.Refresh();
        }

        EditorGUI.EndDisabledGroup();

        CURRENT_TRANSFORM = null;
    }
    /// <summary>
    /// Generate the detail meshes and return the export object
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public static BuildrDetailExportObject Build(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data)
    {
        BuildrDetailExportObject exportObject = new BuildrDetailExportObject();
        List<Texture2D> detailTextures = new List<Texture2D>();
        List<int> detailSubmeshesWithTextures = new List<int>();
        int numberOfDetails = data.details.Count;
        mesh.Clear();
        mesh.subMeshCount = numberOfDetails;

        for(int d = 0; d < numberOfDetails; d++)
        {
            BuildrDetail detail = data.details[d];
            if(detail.mesh == null)
                continue;
            int faceIndex = detail.face;
            Vector3 position = Vector3.zero;
            BuildrPlan plan = data.plan;
            int numberOfVolumes = plan.numberOfVolumes;
            Vector2 faceUv = detail.faceUv;
            Quaternion faceAngle = Quaternion.identity;
            //Place the detail mesh
            if (detail.type == BuildrDetail.Types.Facade)
            {
                //find facade
                int facadeCount = 0;
                bool facadeFound = false;
                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volume = plan.volumes[s];
                    int numberOfVolumePoints = volume.points.Count;
                    for (int p = 0; p < numberOfVolumePoints; p++)
                    {
                        if (facadeCount == faceIndex)
                        {
                            int indexA = p;
                            int indexB = (p + 1) % numberOfVolumePoints;
                            Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                            Vector3 p1 = plan.points[volume.points[indexB]].vector3;
                            Vector3 basePosition = Vector3.Lerp(p0, p1, faceUv.x);
                            Vector3 detailHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight * faceUv.y);
                            Vector3 facadeCross = Vector3.Cross(Vector3.up, p1 - p0).normalized;
                            Vector3 detailDepth = facadeCross * detail.faceHeight;
                            faceAngle = Quaternion.LookRotation(facadeCross);
                            position = basePosition + detailHeight + detailDepth;
                            facadeFound = true;
                            break;
                        }
                        facadeCount++;
                    }
                    if (facadeFound)
                        break;
                }
            }
            else//roof detail
            {
                BuildrVolume volume = plan.volumes[Mathf.Clamp(0,numberOfVolumes-1,faceIndex)];
                int numberOfVolumePoints = volume.points.Count;
                Vector3 minimumRoofPoint = plan.points[volume.points[0]].vector3;
                Vector3 maximumRoofPoint = minimumRoofPoint;
                for (int p = 1; p < numberOfVolumePoints; p++)
                {
                    Vector3 p0 = plan.points[volume.points[p]].vector3;
                    if (p0.x < minimumRoofPoint.x) minimumRoofPoint.x = p0.x;
                    if (p0.z < minimumRoofPoint.y) minimumRoofPoint.y = p0.z;
                    if (p0.x > maximumRoofPoint.x) maximumRoofPoint.x = p0.x;
                    if (p0.z > maximumRoofPoint.y) maximumRoofPoint.y = p0.z;
                }
                position.x = Mathf.Lerp(minimumRoofPoint.x, maximumRoofPoint.x, faceUv.x);
                position.z = Mathf.Lerp(minimumRoofPoint.y, maximumRoofPoint.y, faceUv.y);
                position.y = volume.numberOfFloors * data.floorHeight + detail.faceHeight;
            }

            Quaternion userRotation = Quaternion.Euler(detail.userRotation);
            int vertexCount = detail.mesh.vertexCount;
            Vector3[] verts = new Vector3[vertexCount];
            Quaternion rotate = faceAngle * userRotation;
            for (int i = 0; i < vertexCount; i++)
            {
                Vector3 sourceVertex = Vector3.Scale(detail.mesh.vertices[i], detail.scale);
                Vector3 outputVertex = (rotate) * sourceVertex + position;
                verts[i] = outputVertex;
            }
            mesh.AddData(verts, detail.mesh.uv, detail.mesh.triangles, d);
            detail.worldPosition = position;
            detail.worldRotation = rotate;

            if (detail.material.mainTexture != null)
            {
        #if UNITY_EDITOR
                string texturePath = AssetDatabase.GetAssetPath(detail.material.mainTexture);
                TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath);

                if (!textureImporter.isReadable)
                {
                    Debug.LogWarning("The texture you have selected is not readable. Cannot render");
                    return exportObject;
                }

                detailTextures.Add((Texture2D)detail.material.mainTexture);
                detailSubmeshesWithTextures.Add(d);
        #endif
            }
        }

        if(detailtexture!=null)
            Object.DestroyImmediate(detailtexture);

        List<Mesh> outputMeshes = new List<Mesh>();
        if (detailSubmeshesWithTextures.Count > 0)
        {
            Rect[] textureRects = BuildrTexturePacker2.Pack(out detailtexture, detailTextures.ToArray(), 512);
            if(detailSubmeshesWithTextures.Count > 0) mesh.Atlas(detailSubmeshesWithTextures.ToArray(), textureRects);
            mesh.CollapseSubmeshes();
            mesh.Build();
            int numberOfMeshes = mesh.meshCount;
            for (int i = 0; i < numberOfMeshes; i++)
                outputMeshes.Add(mesh[i].mesh);
        }

        exportObject.detailMeshes = outputMeshes.ToArray();
        exportObject.texture = detailtexture;
        return exportObject;
        /*if (detailMat == null)
                detailMat = new Material(Shader.Find("Diffuse"));
            detailMat.mainTexture = detailtexture;
            List<Mesh> outputMeshes = new List<Mesh>();
            for (int i = 0; i < numberOfMeshes; i++)
            {
                outputMeshes.Add(mesh[i].mesh);
                GameObject details = new GameObject("details " + i);
                details.AddComponent<MeshFilter>().mesh = mesh[i].mesh;
                details.AddComponent<MeshRenderer>().sharedMaterial = detailMat;
                detailGameobjects.Add(details);
            }
        }
        //        Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec");
        return detailGameobjects.ToArray();*/
    }
    //returns the number of meshes
    private static int ExportDetails(BuildrData data)
    {
        DynamicMeshGenericMultiMaterialMesh DET_MESH = new DynamicMeshGenericMultiMaterialMesh();
        BuildrDetailExportObject exportObject = BuildrBuildingDetails.Build(DET_MESH, data);

        int numberOfMeshes = exportObject.detailMeshes.Length;
        if (numberOfMeshes == 0)
            return 0;

        string textureName = data.exportFilename + ATLASED_SUFFIX + DETAIL_SUFFIX;
        string textureFileName = textureName + ".png";
        string newDirectory = ROOT_FOLDER + data.exportFilename;

        File.WriteAllBytes(newDirectory + "/" + textureFileName, exportObject.texture.EncodeToPNG());
        ExportMaterial[] exportTextures = new ExportMaterial[1];
        ExportMaterial newTexture = new ExportMaterial();
        newTexture.name = textureName;
        newTexture.filepath = textureFileName;
        newTexture.generated = true;
        exportTextures[0] = newTexture;
        for(int i = 0; i < numberOfMeshes; i++)
        {
            string DetailSuffixIndex = ((numberOfMeshes > 1) ? "_"+i : "");
            string DetailFileName = data.exportFilename + DETAIL_SUFFIX + DetailSuffixIndex;
            string DetailFolder = ROOT_FOLDER + data.exportFilename + "/";
            Export(DetailFileName, DetailFolder, data, exportObject.detailMeshes[i], exportTextures);
        }

        Texture2D.DestroyImmediate(exportObject.texture);

        return numberOfMeshes;
    }
    private static void ExportLowLOD(BuildrData data)
    {
        DynamicMeshGenericMultiMaterialMesh dynLODMesh = new DynamicMeshGenericMultiMaterialMesh();
        dynLODMesh.subMeshCount = data.textures.Count;
        BuildrBuildingLowDetail2.Build(dynLODMesh, data);
        dynLODMesh.CollapseSubmeshes();
        EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.80f);
        dynLODMesh.Build(data.includeTangents);
        Mesh LODMesh = dynLODMesh[0].mesh;//TODO: support many meshes
        MeshUtility.Optimize(LODMesh);
        EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.90f);

        string textureName = data.exportFilename + ATLASED_SUFFIX + LOD_SUFFIX;
        string textureFileName = textureName + ".png";
        string newDirectory = ROOT_FOLDER + data.exportFilename;

        File.WriteAllBytes(newDirectory + "/" + textureFileName, data.LODTextureAtlas.EncodeToPNG());
        ExportMaterial[] exportTextures = new ExportMaterial[1];
        ExportMaterial newTexture = new ExportMaterial();
        newTexture.name = textureName;
        newTexture.filepath = textureFileName;
        newTexture.generated = true;
        exportTextures[0] = newTexture;
        string LODFileName = data.exportFilename + LOD_SUFFIX;
        string LODFolder = ROOT_FOLDER + data.exportFilename + "/";
        Export(LODFileName, LODFolder, data, LODMesh, exportTextures);

        if (data.placeIntoScene)
        {
            AssetDatabase.Refresh();//ensure the database is up to date...
            string filePath = LODFolder + LODFileName + FILE_EXTENTION;
            GameObject newModel = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadMainAssetAtPath(filePath));
            newModel.transform.position = CURRENT_TRANSFORM.position;
            newModel.transform.rotation = CURRENT_TRANSFORM.rotation;
        }

        Texture2D.DestroyImmediate(data.textureAtlas);
        Texture2D.DestroyImmediate(data.LODTextureAtlas);
    }
    private static void ExportCollider(BuildrData data)
    {
        DynamicMeshGenericMultiMaterialMesh COL_MESH = new DynamicMeshGenericMultiMaterialMesh();
        COL_MESH.subMeshCount = data.textures.Count;
        BuildrBuildingCollider.Build(COL_MESH, data);
        //        COL_MESH.CollapseSubmeshes();
        COL_MESH.Build(false);

        ExportMaterial[] exportTextures = new ExportMaterial[1];
        ExportMaterial newTexture = new ExportMaterial();
        newTexture.name = "blank";
        newTexture.filepath = "";
        newTexture.generated = true;
        exportTextures[0] = newTexture;

        int numberOfColliderMeshes = COL_MESH.meshCount;
        for (int i = 0; i < numberOfColliderMeshes; i++)
        {
            MeshUtility.Optimize(COL_MESH[i].mesh);
            string ColliderSuffixIndex = ((numberOfColliderMeshes > 1) ? "_" + i : "");
            string ColliderFileName = data.exportFilename + COLLIDER_SUFFIX + ColliderSuffixIndex;
            string ColliderFolder = ROOT_FOLDER + data.exportFilename + "/";
            Export(ColliderFileName, ColliderFolder, data, COL_MESH[i].mesh, exportTextures);
        }
    }
 private static void Export(string filename, string folder, BuildrData data, Mesh exportMesh, ExportMaterial[] exportTextures)
 {
     switch (data.filetype)
     {
         case BuildrData.filetypes.obj:
             OBJExporter.Export(folder, filename, exportMesh, exportTextures, data.copyTexturesIntoExportFolder);
             break;
         case BuildrData.filetypes.fbx:
             FBXExporter.Export(folder, filename, exportMesh, exportTextures, data.copyTexturesIntoExportFolder);
             break;
     }
 }
 private static void Export(BuildrData data, Mesh exportMesh, ExportMaterial[] exportTextures)
 {
     Export(data.exportFilename, ROOT_FOLDER + data.exportFilename + "/", data, exportMesh, exportTextures);
 }
示例#51
0
    public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
    {
        if (editMode.fullMesh == null)
        {
            return;
        }

        Rect HUDRect = new Rect(0, 0, 300, 300);

        Handles.BeginGUI();
        GUILayout.BeginArea(HUDRect);

        EditorGUILayout.LabelField("Buildr");
        EditorGUILayout.LabelField("Vertices: " + editMode.fullMesh.vertexCount);
        EditorGUILayout.LabelField("Triangles " + editMode.fullMesh.triangleCount / 3);

        GUILayout.EndArea();
        Handles.EndGUI();

        bool isLegal = !(data.plan.illegalPoints.Length > 0);

        if (isLegal)
        {
            isLegal = editMode.transform.localScale == Vector3.one;
        }

        if (isLegal)
        {
            return;
        }

        int numberOfFacades  = data.facades.Count;
        int numberOfRoofs    = data.roofs.Count;
        int numberOfTextures = data.textures.Count;

        if (numberOfFacades == 0 || numberOfRoofs == 0 || numberOfTextures == 0)
        {
            return;
        }

        Vector3 position = editMode.transform.position;

        BuildrPlan area            = data.plan;
        int        numberOfVolumes = area.numberOfVolumes;

        int facadeCounter = 0;

        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume      = data.plan.volumes[s];
            int          volumeSize  = volume.Count;
            Vector3      floorCentre = Vector3.zero;
            Handles.color = Color.red;

            for (int p = 0; p < volumeSize; p++)
            {
                int     point    = volume.points[p];
                Vector3 pointPos = area.points[point].vector3;
                floorCentre += pointPos;

                List <Vector3> verts        = new List <Vector3>();
                int            indexB       = (p < volumeSize - 1) ? p + 1 : 0;
                Vector3        volumeHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight);
                verts.Add(pointPos + position);
                verts.Add(area.points[volume.points[indexB]].vector3 + position);
                verts.Add(verts[1] + volumeHeight);
                verts.Add(verts[0] + volumeHeight);
                Handles.DrawSolidRectangleWithOutline(verts.ToArray(), new Color(1, 0, 0, 0.2f), Color.red);
                Handles.DrawLine(verts[2], verts[3]);
                facadeCounter++;
            }
        }
    }
    private static void ExportModel(BuildrData data)
    {
        try
        {
            EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.0f);

            //check overwrites...
            string newDirectory = ROOT_FOLDER + data.exportFilename;
            if(!CreateFolder(newDirectory))
            {
                EditorUtility.ClearProgressBar();
                return;
            }

            EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.05f);
            if(data.fullmesh)
            {
                //export unpacked model
                DYN_MESH = new DynamicMeshGenericMultiMaterialMesh();
                DYN_MESH.subMeshCount = data.textures.Count;
                BuildrBuilding.Build(DYN_MESH, data);
                EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.30f);
                BuildrRoof.Build(DYN_MESH, data);
                EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.60f);
                DYN_MESH.Build(data.includeTangents);
                int meshCount = DYN_MESH.meshCount;

                List<int> unusedTextures = DYN_MESH.unusedSubmeshes;
                int numberOfUnpackedTextures = data.textures.Count;
                List<ExportMaterial> exportTextureList = new List<ExportMaterial>();
                for (int t = 0; t < numberOfUnpackedTextures; t++)
                {
                    if (unusedTextures.Contains(t))
                        continue;//skip, unused
                    ExportMaterial newTexture = new ExportMaterial();
                    newTexture.name = data.textures[t].name;
                    newTexture.material = data.textures[t].material;
                    newTexture.generated = false;
                    newTexture.filepath = data.textures[t].filePath;
                    exportTextureList.Add(newTexture);
                }
                for(int i = 0; i < meshCount; i++)
                {
                    EXPORT_MESH = DYN_MESH[i].mesh;
                    MeshUtility.Optimize(EXPORT_MESH);
                    Export(data, EXPORT_MESH, exportTextureList.ToArray());
                    string filenameSuffix = (meshCount>1)? i.ToString() : "";
                    string filename = data.exportFilename + filenameSuffix;
                    Export(filename, ROOT_FOLDER + data.exportFilename + "/", data, EXPORT_MESH, exportTextureList.ToArray());
                }
            }

            //Export Collider
            if(data.generateCollider != BuildrData.ColliderGenerationModes.None)
                ExportCollider(data);

            int[] numberOfInteriorMeshes = new int[data.plan.numberOfVolumes];
            if(data.renderInteriors && data.fullmesh)
                numberOfInteriorMeshes = ExportInteriors(data);

            int[] numberOfStairwells = new int[data.plan.numberOfVolumes];
            if (data.renderInteriors && data.fullmesh)
                numberOfStairwells = ExportStairwells(data);

            int numberOfDetailMeshes = 0;
            if(data.fullmesh)
                numberOfDetailMeshes = ExportDetails(data);

            EditorUtility.DisplayCancelableProgressBar(PROGRESSBAR_TEXT, "", 0.70f);

            //Place exported version into scene
            if(data.fullmesh)
            {
                AssetDatabase.Refresh();//ensure the database is up to date...
                GameObject baseObject = new GameObject(data.exportFilename);
                if((data.createPrefabOnExport || data.placeIntoScene))
                {
                    baseObject.transform.position = CURRENT_TRANSFORM.position;
                    baseObject.transform.rotation = CURRENT_TRANSFORM.rotation;

                    string modelFilePath = ROOT_FOLDER + data.exportFilename + "/" + data.exportFilename + FILE_EXTENTION;
                    GameObject newModel = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadMainAssetAtPath(modelFilePath));
                    newModel.name = "model";
                    newModel.transform.parent = baseObject.transform;
                    newModel.transform.localPosition = Vector3.zero;
                    newModel.transform.localRotation = Quaternion.identity;
                    if(data.generateCollider != BuildrData.ColliderGenerationModes.None)
                    {
                        GameObject colliderObject = new GameObject("collider");
                        string colliderFilePath = ROOT_FOLDER + data.exportFilename + "/" + data.exportFilename + COLLIDER_SUFFIX + FILE_EXTENTION;
                        colliderObject.AddComponent<MeshCollider>().sharedMesh = (Mesh)AssetDatabase.LoadAssetAtPath(colliderFilePath, typeof(Mesh));
                        colliderObject.transform.parent = baseObject.transform;
                        colliderObject.transform.localPosition = Vector3.zero;
                        colliderObject.transform.localRotation = Quaternion.identity;
                    }

                    for (int i = 0; i < numberOfDetailMeshes; i++)
                    {
                        string detailSuffixIndex = ((numberOfDetailMeshes > 1) ? "_" + i : "");
                        string detailFileName = data.exportFilename + DETAIL_SUFFIX + detailSuffixIndex;
                        string detailFolder = ROOT_FOLDER + data.exportFilename + "/";
                        string detailFilepath = detailFolder + detailFileName + FILE_EXTENTION;
                        GameObject detailObject = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadMainAssetAtPath(detailFilepath));
                        detailObject.name = "details";
                        detailObject.transform.parent = baseObject.transform;
                        detailObject.transform.localPosition = Vector3.zero;
                        detailObject.transform.localRotation = Quaternion.identity;
                    }

                    int numberOfVolumes = data.plan.numberOfVolumes;
                    GameObject interiorHolder = new GameObject("interiors");
                    interiorHolder.transform.parent = baseObject.transform;
                    interiorHolder.transform.localPosition = Vector3.zero;
                    interiorHolder.transform.localRotation = Quaternion.identity;
                    for (int v = 0; v < numberOfInteriorMeshes.Length; v++)
                    {
                        int numMeshes = numberOfInteriorMeshes[v];
                        for (int i = 0; i < numMeshes; i++)
                        {
                            string VolumeSuffix = ((numberOfVolumes > 1) ? "_" + v : "");
                            string DetailSuffixIndex = ((numMeshes > 1) ? "_" + i : "");
                            string DetailFileName = data.exportFilename + INTERIOR_SUFFIX + VolumeSuffix + DetailSuffixIndex;
                            string DetailFolder = ROOT_FOLDER + data.exportFilename + "/";
                            string filePath = DetailFolder + DetailFileName + FILE_EXTENTION;
                            GameObject interiorObject = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadMainAssetAtPath(filePath));
                            interiorObject.name = INTERIOR_SUFFIX + VolumeSuffix + DetailSuffixIndex;
                            interiorObject.transform.parent = interiorHolder.transform;
                            interiorObject.transform.localPosition = Vector3.zero;
                            interiorObject.transform.localRotation = Quaternion.identity;
                        }
                    }

                    for(int v = 0; v < numberOfStairwells.Length; v++)
                    {
                        int numMeshes = numberOfStairwells[v];
                        for (int i = 0; i < numMeshes; i++)
                        {
                            string VolumeSuffix = ((numberOfVolumes > 1) ? "_" + v : "");
                            string DetailSuffixIndex = ((numMeshes > 1) ? "_" + i : "");
                            string DetailFileName = data.exportFilename + STAIR_SUFFIX + VolumeSuffix + DetailSuffixIndex;
                            string DetailFolder = ROOT_FOLDER + data.exportFilename + "/";
                            string filePath = DetailFolder + DetailFileName + FILE_EXTENTION;
                            GameObject interiorObject = (GameObject)PrefabUtility.InstantiatePrefab(AssetDatabase.LoadMainAssetAtPath(filePath));
                            interiorObject.name = STAIR_SUFFIX + VolumeSuffix + DetailSuffixIndex;
                            interiorObject.transform.parent = interiorHolder.transform;
                            interiorObject.transform.localPosition = data.plan.volumes[v].stairBaseVector[i];
                            interiorObject.transform.localRotation = Quaternion.identity;
                        }
                    }
                }

                if(data.createPrefabOnExport)
                {
                    string prefabPath = ROOT_FOLDER + data.exportFilename + "/" + data.exportFilename + ".prefab";
                    Object prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
                    if(prefab == null)
                        prefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
                    PrefabUtility.ReplacePrefab(baseObject, prefab, ReplacePrefabOptions.ConnectToPrefab);
                }

                if(!data.placeIntoScene)
                    Object.DestroyImmediate(baseObject);
            }

            if(data.exportLowLOD)
            {
                ExportLowLOD(data);
            }

            DYN_MESH = null;
            EXPORT_MESH = null;

            EditorUtility.ClearProgressBar();
            EditorUtility.UnloadUnusedAssets();

            AssetDatabase.Refresh();
        }catch(System.Exception e)
        {
            Debug.LogError("BuildR Export Error: "+e);
            EditorUtility.ClearProgressBar();
        }
    }
    public static void InspectorGUI(BuildrEditMode editMode, BuildrData _data)
    {

        data = _data;
        Undo.RecordObject(data, "Interior Modified");

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

        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUILayout.LabelField("Render Interior of Building");
        bool renderInterior = EditorGUILayout.Toggle(_data.renderInteriors, GUILayout.Width(15));
        if (renderInterior != _data.renderInteriors)
        {
            _data.renderInteriors = renderInterior;
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUILayout.LabelField("Cull All Building Bays");
        bool cullBays = EditorGUILayout.Toggle(_data.cullBays, GUILayout.Width(15));
        if (cullBays != _data.cullBays)
        {
            _data.cullBays = cullBays;
        }
        EditorGUILayout.EndHorizontal();

        //Floor Height
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Floor height", GUILayout.Width(200));
        float newFloorHeight = EditorGUILayout.FloatField(data.floorHeight, GUILayout.Width(50));
        if (newFloorHeight != data.floorHeight)
        {
            data.floorHeight = newFloorHeight;
        }
        EditorGUILayout.LabelField("metres", GUILayout.Width(50));
        EditorGUILayout.EndHorizontal();

        EditorGUI.BeginDisabledGroup(!renderInterior);

        //Ceiling Height
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Interior Ceiling Height", GUILayout.Width(200));
        float newCeilingHeight = EditorGUILayout.Slider(data.interiorCeilingHeight, 0, 1);
        if (newCeilingHeight != data.interiorCeilingHeight)
        {
            data.interiorCeilingHeight = newCeilingHeight;
        }
        EditorGUILayout.EndHorizontal();

        BuildrPlan plan = data.plan;
        int numberOfVolumes = plan.numberOfVolumes;
        int[] volumeSeletionsList = new int[numberOfVolumes];
        string[] volumeSeletionsStringList = new string[numberOfVolumes];
        for (int s = 0; s < numberOfVolumes; s++)
        {
            volumeSeletionsStringList[s] = ("volume " + s);
            volumeSeletionsList[s] = (s);
        }
        selectedVolumeIndex = EditorGUILayout.IntPopup("Selected Volume", selectedVolumeIndex, volumeSeletionsStringList, volumeSeletionsList, GUILayout.Width(400));
        BuildrVolume volume = plan.volumes[selectedVolumeIndex];


        //Stairs
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Generate Stairs", GUILayout.Width(110));
        volume.generateStairs = EditorGUILayout.Toggle(volume.generateStairs);
        EditorGUILayout.EndHorizontal();

        if(plan.cores.Count == 0)
            EditorGUILayout.HelpBox("There are no building cores defined. Go to floorplan to define one so you can generate a stairwell", MessageType.Error);

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Stair Width", GUILayout.Width(110));
        volume.staircaseWidth = EditorGUILayout.Slider(volume.staircaseWidth, 0.5f, 5.0f);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Minimum Step Riser Value", GUILayout.Width(150));
        volume.stepHeight = EditorGUILayout.Slider(volume.stepHeight, 0.05f, 0.5f);
        EditorGUILayout.EndHorizontal();

        EditorGUI.BeginDisabledGroup(!volume.generateStairs);
        EditorGUILayout.BeginVertical("box");
        EditorGUILayout.LabelField("Stairwell Textures");

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Wall Texture", GUILayout.Width(120));
        volume.stairwellWallTexture = EditorGUILayout.Popup(volume.stairwellWallTexture, textureNames);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Floor Texture", GUILayout.Width(120));
        volume.stairwellFloorTexture = EditorGUILayout.Popup(volume.stairwellFloorTexture, textureNames);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Ceiling Texture", GUILayout.Width(120));
        volume.stairwellCeilingTexture = EditorGUILayout.Popup(volume.stairwellCeilingTexture, textureNames);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Step Texture", GUILayout.Width(120));
        volume.stairwellStepTexture = EditorGUILayout.Popup(volume.stairwellStepTexture, textureNames);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.EndVertical();
        EditorGUI.EndDisabledGroup();

        //Basement floors
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Basement Floors", GUILayout.Width(110));
        EditorGUILayout.LabelField(volume.numberOfBasementFloors.ToString("F0"), GUILayout.Width(40));
        EditorGUI.BeginDisabledGroup(volume.numberOfBasementFloors < 1);
        if (GUILayout.Button("-"))
            volume.numberOfBasementFloors--;
        EditorGUI.EndDisabledGroup();
        if (GUILayout.Button("+"))
            volume.numberOfBasementFloors++;
        EditorGUILayout.EndHorizontal();

        int numberOfFloors = volume.numberOfFloors;
        int numberOfBasementFloors = volume.numberOfBasementFloors;
        int totalNumberOfFloors = numberOfBasementFloors + numberOfFloors;
        int[] floorSeletionsList = new int[totalNumberOfFloors];
        string[] floorSeletionsStringList = new string[totalNumberOfFloors];
        for (int f = -numberOfBasementFloors; f < numberOfFloors; f++)
        {
            int index = f + numberOfBasementFloors;
            if(f>0)
                floorSeletionsStringList[index] = "floor " + f;
            else if(f<0)
                floorSeletionsStringList[index] = "basement " + -f;
            else
                floorSeletionsStringList[index] = "ground floor ";
            floorSeletionsList[index] = (f);
        }
        selectedFloor = EditorGUILayout.IntPopup("Selected Floor", selectedFloor, floorSeletionsStringList, floorSeletionsList, GUILayout.Width(400));
        
        EditorGUILayout.LabelField("Interior Textures");
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Floor Texture", GUILayout.Width(120));
        volume.FloorTexture(selectedFloor, EditorGUILayout.Popup(volume.FloorTexture(selectedFloor), textureNames));
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Wall Texture", GUILayout.Width(120));
        volume.WallTexture(selectedFloor, EditorGUILayout.Popup(volume.WallTexture(selectedFloor), textureNames));
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Ceiling Texture", GUILayout.Width(120));
        volume.CeilingTexture(selectedFloor, EditorGUILayout.Popup(volume.CeilingTexture(selectedFloor), textureNames));
        EditorGUILayout.EndHorizontal();

        if(GUILayout.Button("Use Values for All Floors"))
        {
            int useFloorTextureIndex = volume.FloorTexture(selectedFloor);
            int useWallTextureIndex = volume.WallTexture(selectedFloor);
            int useCeilingTextureIndex = volume.CeilingTexture(selectedFloor);
            for(int f = 0; f < numberOfFloors; f++)
            {
                volume.FloorTexture(f, useFloorTextureIndex);
                volume.WallTexture(f, useWallTextureIndex);
                volume.CeilingTexture(f, useCeilingTextureIndex);
            }
        }

        if (GUILayout.Button("Use Values for Entire Building"))
        {
            int useFloorTextureIndex = volume.FloorTexture(selectedFloor);
            int useWallTextureIndex = volume.WallTexture(selectedFloor);
            int useCeilingTextureIndex = volume.CeilingTexture(selectedFloor);

            for (int v = 0; v < numberOfVolumes; v++)
            {
                BuildrVolume thisvolume = plan.volumes[v];
                int numberOfFloorsToModifiy = thisvolume.numberOfFloors;
                for (int f = 0; f < numberOfFloorsToModifiy; f++)
                {
                    thisvolume.FloorTexture(f, useFloorTextureIndex);
                    thisvolume.WallTexture(f, useWallTextureIndex);
                    thisvolume.CeilingTexture(f, useCeilingTextureIndex);
                }
            }
        }

        EditorGUI.EndDisabledGroup();
    }
    private static int[] ExportStairwells(BuildrData data)
    {
        int numberOfVolumes = data.plan.numberOfVolumes;
        int[] returnNumberOfMeshes = new int[numberOfVolumes];

        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = data.plan.volumes[v];

            int numberOfUnpackedTextures = data.textures.Count;
            List<ExportMaterial> exportTextures = new List<ExportMaterial>();

            if (!volume.generateStairs) continue;
            DynamicMeshGenericMultiMaterialMesh INT_STAIRWELL = new DynamicMeshGenericMultiMaterialMesh();
            INT_STAIRWELL.subMeshCount = data.textures.Count;
            BuildrStairs.Build(INT_STAIRWELL, data, v, BuildrStairs.StairModes.Stepped, true);
            INT_STAIRWELL.Build(data.includeTangents);

            List<int> unusedStairTextures = INT_STAIRWELL.unusedSubmeshes;
            numberOfUnpackedTextures = data.textures.Count;
            for (int t = 0; t < numberOfUnpackedTextures; t++)
            {
                if (unusedStairTextures.Contains(t))
                    continue;//skip, unused
                ExportMaterial newTexture = new ExportMaterial();
                newTexture.name = data.textures[t].name;
                newTexture.material = data.textures[t].material;
                newTexture.generated = false;
                newTexture.filepath = data.textures[t].filePath;
                exportTextures.Add(newTexture);
            }

            int numberOfStairMeshes = INT_STAIRWELL.meshCount;
            for (int i = 0; i < numberOfStairMeshes; i++)
            {
                MeshUtility.Optimize(INT_STAIRWELL[i].mesh);
                string VolumeSuffix = ((numberOfVolumes > 1) ? "_" + v : "");
                string DetailSuffixIndex = ((numberOfStairMeshes > 1) ? "_" + i : "");
                string DetailFileName = data.exportFilename + STAIR_SUFFIX + VolumeSuffix + DetailSuffixIndex;
                string DetailFolder = ROOT_FOLDER + data.exportFilename + "/";
                Export(DetailFileName, DetailFolder, data, INT_STAIRWELL[i].mesh, exportTextures.ToArray());
            }

            returnNumberOfMeshes[v] = numberOfStairMeshes;
        }

        return returnNumberOfMeshes;
    }
    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();
    }
    //private static BuildrData data;

    public static void InspectorGUI(BuildrEditMode editMode, BuildrData _data)
    {
        //ensure that the model exists in the scene
        if (editMode.fullMesh == null)
            editMode.UpdateRender();

        Undo.RecordObject(_data, "Building Modified");
        //texture library string array
        BuildrTexture[] textures = _data.textures.ToArray();
        int numberOfTextures = textures.Length;
        string[] textureNames = new string[numberOfTextures];
        for (int t = 0; t < numberOfTextures; t++)
            textureNames[t] = textures[t].name;

        //Render a full version version
        EditorGUILayout.LabelField("Building Generation Types");
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUI.BeginDisabledGroup(editMode.renderMode == BuildrEditMode.renderModes.full);
        if (GUILayout.Button("Full Detail", GUILayout.Height(28)))
        {
            editMode.UpdateRender(BuildrEditMode.renderModes.full);
        }
        EditorGUI.EndDisabledGroup();

        //Render a low detail version
        EditorGUI.BeginDisabledGroup(editMode.renderMode == BuildrEditMode.renderModes.lowDetail);
        if (GUILayout.Button("Low Detail", GUILayout.Height(28)))
        {
            editMode.UpdateRender(BuildrEditMode.renderModes.lowDetail);
        }
        EditorGUI.EndDisabledGroup();

        //Render a box version
        EditorGUI.BeginDisabledGroup(editMode.renderMode == BuildrEditMode.renderModes.box);
        if (GUILayout.Button("Box Outline", GUILayout.Height(28)))
        {
            editMode.UpdateRender(BuildrEditMode.renderModes.box);
        }
        EditorGUI.EndDisabledGroup();
        EditorGUILayout.EndHorizontal();

        //Toggle showing the wireframe when we have selected the model.
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUILayout.LabelField("Show Wireframe");
        editMode.showWireframe = EditorGUILayout.Toggle(editMode.showWireframe, GUILayout.Width(15));
        EditorGUILayout.EndHorizontal();

        //Tangent calculation
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUI.BeginDisabledGroup(editMode.fullMesh.hasTangents);
        if (GUILayout.Button("Build Tangents", GUILayout.Height(38)))
        {
            if (editMode.fullMesh != null)
                editMode.fullMesh.SolveTangents();
            if(editMode.detailMesh != null)
                editMode.detailMesh.SolveTangents();
            GUI.changed = false;
        }
        EditorGUI.EndDisabledGroup();
        if (!editMode.fullMesh.hasTangents)
            EditorGUILayout.HelpBox("The model doesn't have tangents", MessageType.Warning);
        EditorGUILayout.EndHorizontal();

        //Lightmap rendering
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUI.BeginDisabledGroup(editMode.fullMesh.lightmapUvsCalculated);
        if (GUILayout.Button("Build Lightmap UVs", GUILayout.Height(38)))
        {
//            Undo.RegisterSceneUndo("Build Lightmap UVs");
            if(editMode.fullMesh != null)
            {
                for (int i = 0; i < editMode.fullMesh.meshCount; i++)
                    Unwrapping.GenerateSecondaryUVSet(editMode.fullMesh[i].mesh);}
                editMode.fullMesh.lightmapUvsCalculated = true;
            if(editMode.detailMesh != null)
            {
                for (int i = 0; i < editMode.detailMesh.meshCount; i++)
                    Unwrapping.GenerateSecondaryUVSet(editMode.detailMesh[i].mesh);
                editMode.detailMesh.lightmapUvsCalculated = true;
            }
            int numberOfInteriors = editMode.interiorMeshes.Count;
            for(int i = 0; i < numberOfInteriors; i++)
            {
                DynamicMeshGenericMultiMaterialMesh interiorMesh = editMode.interiorMeshes[i];
                for (int j = 0; j < interiorMesh.meshCount; j++)
                    Unwrapping.GenerateSecondaryUVSet(interiorMesh[j].mesh);
                interiorMesh.lightmapUvsCalculated = true;
            }
            GUI.changed = false;
        }
        EditorGUI.EndDisabledGroup();
        if (!editMode.fullMesh.lightmapUvsCalculated)
            EditorGUILayout.HelpBox("The model doesn't have lightmap UVs", MessageType.Warning);
        EditorGUILayout.EndHorizontal();

        //Mesh Optimisation
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUI.BeginDisabledGroup(editMode.fullMesh.optimised);
        if (GUILayout.Button("Optimise Mesh For Runtime", GUILayout.Height(38)))
        {
//            Undo.RegisterSceneUndo("Optimise Mesh");
            if (editMode.fullMesh != null)
            {
                for (int i = 0; i < editMode.fullMesh.meshCount; i++)
                    MeshUtility.Optimize(editMode.fullMesh[i].mesh);
                editMode.fullMesh.optimised = true;
            }

            if (editMode.detailMesh != null)
            {
                for(int i = 0; i < editMode.detailMesh.meshCount; i++)
                    MeshUtility.Optimize(editMode.detailMesh[i].mesh);
                editMode.detailMesh.optimised = true;
            }
            GUI.changed = false;
        }
        EditorGUI.EndDisabledGroup();
        if (!editMode.fullMesh.optimised)
            EditorGUILayout.HelpBox("The model is currently fully optimised for runtime", MessageType.Warning);
        EditorGUILayout.EndHorizontal();

        //Underside render toggle
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUILayout.LabelField("Render Underside of Building");
        bool drawUnderside = EditorGUILayout.Toggle(_data.drawUnderside, GUILayout.Width(15));
        if(drawUnderside != _data.drawUnderside)
        {
            _data.drawUnderside = drawUnderside;
        }
        EditorGUILayout.EndHorizontal();

        //Define the height of foundations if you need them
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUILayout.LabelField("Foundation Height", GUILayout.Width(120));
        _data.foundationHeight = EditorGUILayout.Slider(_data.foundationHeight, 0, 25);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Foundation Texture", GUILayout.Width(120));
        _data.foundationTexture = EditorGUILayout.Popup(_data.foundationTexture, textureNames, GUILayout.Width(260));
        EditorGUILayout.EndHorizontal();

        //Collider mesh
        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
        EditorGUILayout.LabelField("Generate Collider");
        _data.generateCollider = (BuildrData.ColliderGenerationModes)EditorGUILayout.EnumPopup(_data.generateCollider);
        EditorGUILayout.EndHorizontal();

        //One draw call mesh  -TODO
//        EditorGUILayout.BeginHorizontal(GUILayout.Width(400));
//        EditorGUILayout.LabelField("One Draw Call");
//        _data.oneDrawCall = EditorGUILayout.Toggle(_data.oneDrawCall);
//        EditorGUILayout.EndHorizontal();

        for (int i = 0; i < editMode.fullMesh.meshCount; i++)
            EditorUtility.SetSelectedWireframeHidden(editMode.meshHolders[i].GetComponent<Renderer>(), !editMode.showWireframe);
    }
示例#57
0
 public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
 {
     Build(_mesh, _data, false);
 }
    public static void SceneGUI(BuildrEditMode _editMode, BuildrData _data, bool shouldSnap, float handleSize)
    {
        Vector3 camDirection = Camera.current.transform.forward;
        Vector3 camPosition = Camera.current.transform.position;
        Vector3 position = _editMode.transform.position;
        data = _data;
        BuildrPlan plan = data.plan;
        BuildrVolume selectedVolume = plan.volumes[selectedVolumeIndex];
        int selectedVolumeSize = selectedVolume.Count;
        Handles.color = Color.white;
        int facadeCounter = 0;

        GUIStyle whiteLabelStyle = new GUIStyle();
        whiteLabelStyle.normal.textColor = Color.white;
        whiteLabelStyle.alignment = TextAnchor.MiddleCenter;
        whiteLabelStyle.fixedWidth = 75.0f;

        int numberOfVolumes = plan.numberOfVolumes;
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = data.plan.volumes[s];
            int volumeSize = volume.Count;
            Vector3 floorCentre = Vector3.zero;

            for (int p = 0; p < volumeSize; p++)
            {
                int point = volume.points[p];
                Vector3 pointPos = plan.points[point].vector3;
                floorCentre += pointPos;
            }
            floorCentre /= volumeSize;

            if(s==selectedVolumeIndex)
            {
                whiteLabelStyle.normal.textColor = BuildrColours.RED;
                whiteLabelStyle.fontStyle = FontStyle.Bold;
            }
            else
            {
                whiteLabelStyle.normal.textColor = Color.white;
                whiteLabelStyle.fontStyle = FontStyle.Normal;
            }

            //Volume height/floor number slider
            Vector3 volumeHeightDir = Vector3.up * (volume.numberOfFloors * data.floorHeight);
            Vector3 volumePosition = floorCentre + position + volumeHeightDir;
            Handles.color = Color.white;
            if (Vector3.Dot(camDirection, volumePosition - camPosition) > 0)//only display label when facade is facing camera
            {
                Handles.Label(volumePosition + (Vector3.up * (handleSize * 0.1f)), "volume " + s, whiteLabelStyle);
            }
        }
        whiteLabelStyle.normal.textColor = Color.white;
        whiteLabelStyle.fontStyle = FontStyle.Normal;

        for (int p = 0; p < selectedVolumeSize; p++)
        {
            int point = selectedVolume.points[p];
            Vector3 pointPos = plan.points[point].vector3;

            List<Vector3> verts = new List<Vector3>();
            int indexB = (p < selectedVolumeSize - 1) ? p + 1 : 0;
            Vector3 floorHeightVector = Vector3.up * (selectedFloor * data.floorHeight);
            Vector3 ceilingHeightVector = Vector3.up * ((selectedFloor+1) * data.floorHeight);
            Vector3 p0 = pointPos + position;
            Vector3 p1 = plan.points[selectedVolume.points[indexB]].vector3 + position;
            verts.Add(pointPos + position);
            verts.Add(plan.points[selectedVolume.points[indexB]].vector3 + position);
            verts.Add(verts[1] + floorHeightVector);
            verts.Add(verts[0] + floorHeightVector);
            Handles.color = BuildrColours.RED;
            Handles.DrawLine(p0 + floorHeightVector, p1 + floorHeightVector);
            Handles.DrawLine(p0 + ceilingHeightVector, p1 + ceilingHeightVector);
            Handles.DrawLine(p0 + floorHeightVector, p0 + ceilingHeightVector);
            if (_editMode.showFacadeMarkers)
            {
                Handles.color = Color.white;
                Vector3 facadeDirection = Vector3.Cross((verts[0] - verts[1]), Vector3.up);
                Vector3 centerPos = (verts[0] + verts[1]) * 0.5f;
                bool camVisible = Vector3.Dot(camDirection, centerPos - camPosition) > 0;
                bool facadeVisible = Vector3.Dot(camDirection, facadeDirection) < 0;
                if (camVisible && facadeVisible)//only display label when facade is facing camera and is in camera view
                {
                    Vector3 labelPos = centerPos + facadeDirection.normalized;
                    Handles.Label(labelPos, "facade " + facadeCounter, whiteLabelStyle);
                    Handles.DrawLine(centerPos, labelPos);
                }
            }
            facadeCounter++;
        }
    }
示例#59
0
    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();
    }
 public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
 {
 }