示例#1
0
 public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
 {
     if (GUI.changed)
     {
         EditorUtility.SetDirty(editMode);
         EditorUtility.SetDirty(data);
         editMode.UpdateRender();
     }
 }
示例#2
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();
        }
    }
示例#3
0
    void OnSceneGUI()
    {
        if (SceneView.focusedWindow == null)
        {
            return;
        }

        if (_data == null)
        {
            _data = _editMode.data;
            return;
        }

        _position   = _editMode.transform.position;
        _handleSize = HandleUtility.GetHandleSize(_position);

        if (_editMode.alwaysSnap)
        {
            _shouldSnap = true;
        }
        else
        {
            _shouldSnap = Event.current.shift;
        }

        if (_data.editing)
        {
            switch (_editMode.stage)
            {
            case BuildrEditMode.stages.floorplan:
                BuildrEditModeFloorplan.SceneGUI(_editMode, _data.plan, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.building:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                BuildrEditModeBuilding.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.facades:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.textures:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                BuildrEditModeTextures.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.roofs:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.details:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                BuildrEditModeDetails.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.interior:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                BuildrEditModeInterior.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.options:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;

            case BuildrEditMode.stages.export:
                BuildrEditModeHUD.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
                break;
            }
        }
        else
        {
            BuildrGenerateModeEditor.SceneGUI(_editMode, _data, _shouldSnap, _handleSize);
        }

        if (GUI.changed)
        {
            EditorUtility.SetDirty(_editMode);
            EditorUtility.SetDirty(_data);
            _editMode.UpdateRender();
        }
    }
    //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);
    }
示例#5
0
    //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);
        }
    }
    public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
    {
        if (data.details.Count == 0)
            return;
        Undo.RecordObject(data, "Detail Modified");

        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 plan = data.plan;
        int numberOfVolumes = plan.numberOfVolumes;
        BuildrDetail bDetail = data.details[selectedDetail];
        float volumeHeight = 0;
        Vector3 baseLeft = Vector3.zero;
        Vector3 baseRight = Vector3.zero;
        int faceIndex = bDetail.face;

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

            for (int p = 0; p < volumeSize; p++)
            {
                int point = volume.points[p];
                int indexB = volume.points[(p + 1) % volumeSize];
                Vector3 fb0 = plan.points[point].vector3;
                Vector3 fb1 = plan.points[indexB].vector3;
                if (bDetail.face == facadeCounter && bDetail.type == BuildrDetail.Types.Facade)
                {
                    baseLeft = fb0;
                    baseRight = fb1;
                }
                floorCentre += baseLeft;

                List<Vector3> verts = new List<Vector3>();
                volumeHeight = (volume.numberOfFloors * data.floorHeight);
                Vector3 volumeHeightVector = Vector3.up * volumeHeight;
                verts.Add(fb0 + position);
                verts.Add(fb1 + position);
                verts.Add(verts[1] + volumeHeightVector);
                verts.Add(verts[0] + volumeHeightVector);
                if (bDetail.face == facadeCounter && bDetail.type == BuildrDetail.Types.Facade)
                    //display something to highlight this facade
                    Handles.DrawSolidRectangleWithOutline(verts.ToArray(), Color.clear, BuildrColours.MAGENTA);
                Handles.color = BuildrColours.CYAN;
                if (v == bDetail.face && bDetail.type == BuildrDetail.Types.Roof)
                    Handles.DrawLine(verts[2], verts[3]);
                if (editMode.showFacadeMarkers)
                {
                    Handles.color = Color.white;
                    Vector3 camDirection = Camera.current.transform.forward;
                    Vector3 facadeDirection = Vector3.Cross((verts[0] - verts[1]), Vector3.up);
                    GUIStyle facadeLabelStyle = new GUIStyle();
                    facadeLabelStyle.normal.textColor = Color.white;
                    facadeLabelStyle.alignment = TextAnchor.MiddleCenter;
                    facadeLabelStyle.fixedWidth = 75.0f;
                    if (Vector3.Dot(camDirection, facadeDirection) < 0)//only display label when facade is facing camera
                    {
                        Vector3 centerPos = (verts[0] + verts[1]) * 0.5f;
                        Vector3 labelPos = centerPos + facadeDirection.normalized;
                        Handles.Label(labelPos, "facade " + facadeCounter, facadeLabelStyle);
                        Handles.DrawLine(centerPos, labelPos);
                    }
                }
                facadeCounter++;
            }
        }

        Vector3 handlePosition = bDetail.worldPosition + position;// new Vector3(basePos.x, volumeHeight * bDetail.faceUv.y, basePos.z);
        Vector3 baseDir = (baseRight - baseLeft).normalized;
                Vector3 baseCross = Vector3.Cross(Vector3.up, baseDir);
        Quaternion currentRot = Quaternion.Euler(bDetail.userRotation);
        Quaternion faceRotation = (bDetail.type == BuildrDetail.Types.Facade) ? Quaternion.LookRotation(baseCross) : Quaternion.identity;

        switch (Tools.current)
        {
            case Tool.Move:
                Vector3 dirX, dirY, dirZ;
                if (bDetail.type == BuildrDetail.Types.Facade)
                {
                    dirX = baseDir;
                    dirY = baseCross;
                    dirZ = Vector3.up;
                }
                else
                {
                    dirX = Vector3.right;
                    dirY = Vector3.up;
                    dirZ = Vector3.forward;
                }
                Vector3 newSliderPos;
                Handles.color = BuildrColours.RED;
                newSliderPos = Handles.Slider(handlePosition, dirX, handleSize * 0.666f, Handles.ArrowCap, 0.0f);
                Handles.color = BuildrColours.BLUE;
                newSliderPos = Handles.Slider(newSliderPos, dirZ, handleSize * 0.666f, Handles.ArrowCap, 0.0f);
                Handles.color = BuildrColours.GREEN;
                newSliderPos = Handles.Slider(newSliderPos, dirY, handleSize * 0.666f, Handles.ArrowCap, 0.0f);
                Vector3 sliderDiff = newSliderPos - handlePosition;

                if (sliderDiff != Vector3.zero)
                {
                    float newXUV = 0, newYUV = 0, newHeight = bDetail.faceHeight;
                    if (bDetail.type == BuildrDetail.Types.Facade)
                    {
                        float facadeWidth = Vector3.Distance(baseLeft, baseRight);
                        float sliderDiffX = Mathf.Sqrt(sliderDiff.x * sliderDiff.x + sliderDiff.z * sliderDiff.z) * Mathf.Sign(Vector3.Dot(baseDir, sliderDiff));
                        newXUV = sliderDiffX / facadeWidth + bDetail.faceUv.x;
                        newYUV = sliderDiff.y / volumeHeight + bDetail.faceUv.y;
                    }
                    else
                    {
                        BuildrVolume volume = plan.volumes[faceIndex];
                        int numberOfVolumePoints = volume.points.Count;
                        Vector3 minPoint = plan.points[volume.points[0]].vector3;
                        Vector3 maxPoint = plan.points[volume.points[0]].vector3;
                        for (int p = 1; p < numberOfVolumePoints; p++)
                        {
                            Vector3 fp0 = plan.points[volume.points[p]].vector3;
                            if (fp0.x < minPoint.x) minPoint.x = fp0.x;
                            if (fp0.z < minPoint.z) minPoint.z = fp0.z;
                            if (fp0.x > maxPoint.x) maxPoint.x = fp0.x;
                            if (fp0.z > maxPoint.z) maxPoint.z = fp0.z;
                        }
                        float roofWidth = maxPoint.x - minPoint.x;
                        float roofDepth = maxPoint.z - minPoint.z;
                        newXUV = sliderDiff.x / roofWidth + bDetail.faceUv.x;
                        newYUV = sliderDiff.z / roofDepth + bDetail.faceUv.y;
                        newHeight += sliderDiff.y;
                    }
                    bDetail.faceUv = new Vector2(newXUV, newYUV);
                    bDetail.faceHeight = newHeight;
                }
                break;

                case Tool.Rotate:
                currentRot = Handles.RotationHandle(currentRot, handlePosition);
                bDetail.userRotation = currentRot.eulerAngles;
                break;

                case Tool.Scale:
                bDetail.scale = Handles.ScaleHandle(bDetail.scale, handlePosition, currentRot * faceRotation, handleSize * 0.666f);

                break;
        }

        //draw mesh bounds
        if (bDetail.mesh != null)
        {
            Bounds meshBounds = bDetail.mesh.bounds;
            Quaternion rotation = bDetail.worldRotation;
            Vector3 p0 = rotation * (new Vector3(meshBounds.min.x, meshBounds.min.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3 p1 = rotation * (new Vector3(meshBounds.max.x, meshBounds.min.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3 p2 = rotation * (new Vector3(meshBounds.min.x, meshBounds.min.y, meshBounds.max.z)) + bDetail.worldPosition;
            Vector3 p3 = rotation * (new Vector3(meshBounds.max.x, meshBounds.min.y, meshBounds.max.z)) + bDetail.worldPosition;
            Vector3 p4 = rotation * (new Vector3(meshBounds.min.x, meshBounds.max.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3 p5 = rotation * (new Vector3(meshBounds.max.x, meshBounds.max.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3 p6 = rotation * (new Vector3(meshBounds.min.x, meshBounds.max.y, meshBounds.max.z)) + bDetail.worldPosition;
            Vector3 p7 = rotation * (new Vector3(meshBounds.max.x, meshBounds.max.y, meshBounds.max.z)) + bDetail.worldPosition;

            Handles.color = BuildrColours.BLUE;
            Handles.DrawLine(p0, p1);
            Handles.DrawLine(p0, p2);
            Handles.DrawLine(p1, p3);
            Handles.DrawLine(p2, p3);
            Handles.DrawLine(p0, p4);
            Handles.DrawLine(p1, p5);
            Handles.DrawLine(p2, p6);
            Handles.DrawLine(p3, p7);
            Handles.DrawLine(p4, p5);
            Handles.DrawLine(p4, p6);
            Handles.DrawLine(p5, p7);
            Handles.DrawLine(p6, p7);

            if (clickPlace)
            {
                Vector3 planeBase = Vector3.zero;
                Vector3 planeNormal = Vector3.up;
                Vector3 planeSize = Vector3.zero;
                if (bDetail.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 fp0 = plan.points[volume.points[indexA]].vector3;
                                Vector3 fp1 = plan.points[volume.points[indexB]].vector3;
                                planeBase = fp0;
                                planeNormal = Vector3.Cross(Vector3.up, fp1 - fp0).normalized;
                                planeSize.x = Vector3.Distance(fp0, fp1);
                                planeSize.y = volume.numberOfFloors * data.floorHeight;
                                facadeFound = true;
                                break;
                            }
                            facadeCount++;
                        }
                        if (facadeFound)
                            break;
                    }
                }
                else
                {
                    BuildrVolume volume = plan.volumes[faceIndex];
                    int numberOfVolumePoints = volume.points.Count;
                    Vector3 minPoint = plan.points[volume.points[0]].vector3;
                    Vector3 maxPoint = plan.points[volume.points[0]].vector3;
                    for (int p = 1; p < numberOfVolumePoints; p++)
                    {
                        Vector3 fp0 = plan.points[volume.points[p]].vector3;
                        if (fp0.x < minPoint.x) minPoint.x = fp0.x;
                        if (fp0.z < minPoint.z) minPoint.z = fp0.z;
                        if (fp0.x > maxPoint.x) maxPoint.x = fp0.x;
                        if (fp0.z > maxPoint.z) maxPoint.z = fp0.z;
                    }
                    planeSize.x = maxPoint.x - minPoint.x;
                    planeSize.z = maxPoint.z - minPoint.z;
                    planeBase = minPoint;
                    planeBase.y = (data.floorHeight * volume.numberOfFloors);
                }
                float distance;
                Plane buildingPlane = new Plane(planeNormal, planeBase);
                Ray ray = Camera.current.ScreenPointToRay(new Vector3(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 30, 0));
                if (buildingPlane.Raycast(ray, out distance))
                {
                    Vector3 mousePlanePoint = ray.GetPoint(distance);
                    Quaternion mouseLookDirection = Quaternion.LookRotation(buildingPlane.normal);

                    if (Handles.Button(mousePlanePoint, mouseLookDirection, handleSize * 0.1f, handleSize * 0.1f, Handles.CircleCap))
                    {
                        float xUv, yUv;
                        if (bDetail.type == BuildrDetail.Types.Facade)
                        {
                            Vector3 facadeBaseMousePoint = new Vector3(mousePlanePoint.x, 0, mousePlanePoint.z);
                            xUv = Vector3.Distance(planeBase, facadeBaseMousePoint) / planeSize.x;
                            yUv = (mousePlanePoint.y - planeBase.y) / planeSize.y;
                        }
                        else
                        {
                            xUv = (mousePlanePoint.x - planeBase.x) / planeSize.x;
                            yUv = (mousePlanePoint.z - planeBase.z) / planeSize.z;
                        }
                        bDetail.faceUv = new Vector2(xUv, yUv);
                        clickPlace = false;
                        GUI.changed = true;
                    }
                }
            }
        }

        if (GUI.changed)
        {
            EditorUtility.SetDirty(editMode);
            EditorUtility.SetDirty(data);
            editMode.UpdateRender();
        }
    }
 public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
 {
     if (GUI.changed)
     {
         EditorUtility.SetDirty(editMode);
         EditorUtility.SetDirty(data);
         editMode.UpdateRender();
     }
 }
示例#8
0
    public static void GeneralOptionsInspector()
    {
        if (constraints == null)
        {
            data.generatorConstraints = ScriptableObject.CreateInstance <BuildrGenerateConstraints>();
            data.generatorConstraints.Init();
            constraints = data.generatorConstraints;
        }

        EditorGUILayout.BeginHorizontal("box");
        EditorGUILayout.LabelField("Saved constraints", GUILayout.Width(110));
        int numberOfFiles = xmlfilelist.Count;

        string[] fileNames = new string[numberOfFiles];
        for (int t = 0; t < numberOfFiles; t++)
        {
            string   filepath      = xmlfilelist[t];
            string[] filepathsplit = filepath.Split(filenameDelimiters);
            string   displayPath   = filepathsplit[filepathsplit.Length - 1];
            fileNames[t] = displayPath;
        }
        int newSelectedFile = EditorGUILayout.Popup(selectedFile, fileNames);

        if (newSelectedFile != selectedFile)
        {
            if (EditorUtility.DisplayDialog("Load Constraints", "Are you sure you want to load a set of constraints from file?", "Yes", "Mmm, no."))
            {
                selectedFile = newSelectedFile;
                dataFilePath = xmlfilelist[selectedFile];
                LoadConstraints();
            }
        }

        if (GUILayout.Button("Load"))
        {
            LoadConstraints();
        }
        if (GUILayout.Button("Save"))
        {
            SaveConstraints();
        }
        if (GUILayout.Button("Save As"))
        {
            SaveConstraintsAs();
        }
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Seed", GUILayout.Width(100));
        constraints.useSeed = EditorGUILayout.Toggle(constraints.useSeed);
        EditorGUI.BeginDisabledGroup(!constraints.useSeed);
        constraints.seed = EditorGUILayout.IntField(constraints.seed);
        EditorGUI.EndDisabledGroup();
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Floor Height", GUILayout.Width(140));
        EditorGUILayout.LabelField(constraints.minimumFloorHeight.ToString(), GUILayout.Width(35));
        EditorGUILayout.MinMaxSlider(ref constraints.minimumFloorHeight, ref constraints.maximumFloorHeight, 2.0f, 3.8f);
        EditorGUILayout.LabelField(constraints.maximumFloorHeight.ToString(), GUILayout.Width(35));
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Constrain Maximum Height", GUILayout.Width(170));
        constraints.constrainHeight = EditorGUILayout.Toggle(constraints.constrainHeight);
        EditorGUI.BeginDisabledGroup(!constraints.constrainHeight);
        EditorGUILayout.BeginVertical();
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Minimum:", GUILayout.Width(70));
        constraints.minimumHeight = EditorGUILayout.FloatField(constraints.minimumHeight, GUILayout.Width(30));
        EditorGUILayout.LabelField("metres", GUILayout.Width(53));
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Maximum:", GUILayout.Width(70));
        constraints.maximumHeight = EditorGUILayout.FloatField(constraints.maximumHeight, GUILayout.Width(30));
        EditorGUILayout.LabelField("metres", GUILayout.Width(53));
        EditorGUILayout.EndHorizontal();
        EditorGUI.EndDisabledGroup();
        EditorGUILayout.EndVertical();
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Constrain Generated Floorplan", GUILayout.Width(200));
        constraints.constrainPlanByArea = EditorGUILayout.Toggle(constraints.constrainPlanByArea);
        EditorGUILayout.EndHorizontal();
        EditorGUI.BeginDisabledGroup(!constraints.constrainPlanByArea);
        EditorGUILayout.LabelField("Contraint Area");
        constraints.area = EditorGUILayout.RectField(constraints.area);
        EditorGUI.EndDisabledGroup();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Texture Pack", GUILayout.Width(100));
        //Debug.Log("InspectorGUI " + constraints.texturePackXML + " " + xmltexturefilelist.IndexOf(constraints.texturePackXML));
        selectedTextureFile = xmltexturefilelist.IndexOf(constraints.texturePackXML);
        int numberTextureOfFiles = xmltexturefilelist.Count;

        string[] textureFileNames = new string[numberTextureOfFiles];
        for (int t = 0; t < numberTextureOfFiles; t++)
        {
            string   filepath      = xmltexturefilelist[t];
            string[] filepathsplit = filepath.Split(filenameDelimiters);
            string   displayPath   = filepathsplit[filepathsplit.Length - 1];
            textureFileNames[t] = displayPath;
        }
        int newSelectedTextureFile = EditorGUILayout.Popup(selectedTextureFile, textureFileNames);

        if (newSelectedTextureFile != selectedTextureFile)
        {
            selectedTextureFile        = newSelectedTextureFile;
            constraints.texturePackXML = xmltexturefilelist[selectedTextureFile];
            BuildrBuildingGenerator.RefreshTextures(data);
        }

        if (GUILayout.Button("Edit Texture Packs"))
        {
            EditorWindow textureEditor = EditorWindow.GetWindow <BuildrBuiltInTextureEditor>(true);
            textureEditor.minSize = new Vector2(280f, 490f);
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal("box");
        EditorGUILayout.BeginVertical();
        EditorGUILayout.LabelField("Design Choices", GUILayout.Width(100));
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.BeginVertical();
        constraints.rowStyled    = EditorGUILayout.Toggle("Row Styles", constraints.rowStyled);
        constraints.columnStyled = EditorGUILayout.Toggle("Column Styles", constraints.columnStyled);
//        constraints.externalAirConUnits = EditorGUILayout.Toggle("External Air Conditioner Units", constraints.rowStyled);
        constraints.splitLevel    = EditorGUILayout.Toggle("Split Level Volume", constraints.splitLevel);
        constraints.taperedLevels = EditorGUILayout.Toggle("Tapered Volume", constraints.taperedLevels);
        EditorGUILayout.EndVertical();
        EditorGUILayout.BeginVertical();
        constraints.singleLevel     = EditorGUILayout.Toggle("Single Volume Level", constraints.singleLevel);
        constraints.atticDesign     = EditorGUILayout.Toggle("Attic Design", constraints.atticDesign);
        constraints.shopGroundFloor = EditorGUILayout.Toggle("Shop Design", constraints.shopGroundFloor);
        EditorGUILayout.EndVertical();
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.EndVertical();
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();

        //FACADE CONSTRAINTS
        int styleLabelSize = 130;

        EditorGUILayout.BeginVertical("box");
        showFacadeConstraints = EditorGUILayout.Foldout(showFacadeConstraints, "Facade Constraints");
        if (showFacadeConstraints)
        {
            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Bay Width", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.openingMinimumWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.openingMinimumWidth, ref constraints.openingMaximumWidth, 0.5f, 2.0f);
            EditorGUILayout.LabelField(constraints.openingMaximumWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Bay Height", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.openingMinimumHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.openingMinimumHeight, ref constraints.openingMaximumHeight, 0.5f, constraints.maximumFloorHeight);
            EditorGUILayout.LabelField(constraints.openingMaximumHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Bay Spacing", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.minimumBayMinimumWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.minimumBayMinimumWidth, ref constraints.minimumBayMaximumWidth, 0.125f, 2.0f);
            EditorGUILayout.LabelField(constraints.minimumBayMaximumWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Bay Opening Depth", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.openingMinimumDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.openingMinimumDepth, ref constraints.openingMaximumDepth, -0.70f, 0.70f);
            EditorGUILayout.LabelField(constraints.openingMaximumDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Facade Depth", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.facadeMinimumDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.facadeMinimumDepth, ref constraints.facadeMaximumDepth, -0.5f, 0.5f);
            EditorGUILayout.LabelField(constraints.facadeMaximumDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Space();

        //ROOF CONSTRAINTS

        EditorGUILayout.BeginVertical("box");
        showRoofConstraints = EditorGUILayout.Foldout(showRoofConstraints, "Roof Constraints");
        if (showRoofConstraints)
        {
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Height", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.minimumRoofHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.minimumRoofHeight, ref constraints.maximumRoofHeight, 1.0f, constraints.maximumFloorHeight);
            EditorGUILayout.LabelField(constraints.maximumRoofHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Mansard Face Depth", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.minimumRoofDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.minimumRoofDepth, ref constraints.maximumRoofDepth, 0.0f, 1.0f);
            EditorGUILayout.LabelField(constraints.maximumRoofDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Mansard Floor Depth", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.minimumRoofFloorDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.minimumRoofFloorDepth, ref constraints.maximumRoofFloorDepth, 0.0f, 1.0f);
            EditorGUILayout.LabelField(constraints.maximumRoofFloorDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.BeginVertical();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Flat Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleFlat = EditorGUILayout.Toggle(constraints.roofStyleFlat);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Mansard Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleMansard = EditorGUILayout.Toggle(constraints.roofStyleMansard);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Barrel Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleBarrel = EditorGUILayout.Toggle(constraints.roofStyleBarrel);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Gabled Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleGabled = EditorGUILayout.Toggle(constraints.roofStyleGabled);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.EndVertical();
            EditorGUILayout.BeginVertical();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Hipped Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleHipped = EditorGUILayout.Toggle(constraints.roofStyleHipped);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Lean To Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleLeanto = EditorGUILayout.Toggle(constraints.roofStyleLeanto);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Steepled Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleSteepled = EditorGUILayout.Toggle(constraints.roofStyleSteepled);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Sawtooth Roof Styles", GUILayout.Width(styleLabelSize));
            constraints.roofStyleSawtooth = EditorGUILayout.Toggle(constraints.roofStyleSawtooth);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.EndVertical();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Allow Dormers", GUILayout.Width(styleLabelSize));
            constraints.allowDormers = EditorGUILayout.Toggle(constraints.allowDormers, GUILayout.Width(30));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space();

            EditorGUI.BeginDisabledGroup(!constraints.allowDormers);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Dormer Chance", GUILayout.Width(150));
            constraints.dormerChance = EditorGUILayout.FloatField(constraints.dormerChance, GUILayout.Width(30));
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Dormer Width", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.dormerMinimumWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.dormerMinimumWidth, ref constraints.dormerMaximumWidth, 0.5f, 2.0f);
            EditorGUILayout.LabelField(constraints.dormerMaximumWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Dormer Height", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.dormerMinimumHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.dormerMinimumHeight, ref constraints.dormerMaximumHeight, 0.5f, 2.0f);
            EditorGUILayout.LabelField(constraints.dormerMaximumHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Dormer Roof Height", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.dormerMinimumRoofHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.dormerMinimumRoofHeight, ref constraints.dormerMaximumRoofHeight, 0.5f, 2.0f);
            EditorGUILayout.LabelField(constraints.dormerMaximumRoofHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Dormer Spacing", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.dormerMinimumSpacing.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.dormerMinimumSpacing, ref constraints.dormerMaximumSpacing, 0.5f, 3.0f);
            EditorGUILayout.LabelField(constraints.dormerMaximumSpacing.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();
            EditorGUI.EndDisabledGroup();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Allow Parapets", GUILayout.Width(styleLabelSize));
            constraints.allowParapet = EditorGUILayout.Toggle(constraints.allowParapet, GUILayout.Width(30));
            EditorGUILayout.EndHorizontal();

            EditorGUI.BeginDisabledGroup(!constraints.allowParapet);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Parapet Render Chance", GUILayout.Width(150));
            constraints.parapetChance = EditorGUILayout.FloatField(constraints.parapetChance, GUILayout.Width(30));
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Parapet Width", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.parapetMinimumDesignWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.parapetMinimumDesignWidth, ref constraints.parapetMaximumDesignWidth, 0.0f, 1.0f);
            EditorGUILayout.LabelField(constraints.parapetMaximumDesignWidth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Parapet Height", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.parapetMinimumHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.parapetMinimumHeight, ref constraints.parapetMaximumHeight, 0.0f, 1.0f);
            EditorGUILayout.LabelField(constraints.parapetMaximumHeight.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Parapet Front Depth", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.parapetMinimumFrontDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.parapetMinimumFrontDepth, ref constraints.parapetMaximumFrontDepth, -1.0f, 1.0f);
            EditorGUILayout.LabelField(constraints.parapetMaximumFrontDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Parapet Back Depth", GUILayout.Width(styleLabelSize));
            EditorGUILayout.LabelField(constraints.parapetMinimumBackDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.MinMaxSlider(ref constraints.parapetMinimumBackDepth, ref constraints.parapetMaximumBackDepth, -1.0f, 1.0f);
            EditorGUILayout.LabelField(constraints.parapetMaximumBackDepth.ToString(), GUILayout.Width(35));
            EditorGUILayout.EndHorizontal();
            EditorGUI.EndDisabledGroup();
        }


        EditorGUILayout.EndVertical();

        if (GUILayout.Button("Generate", GUILayout.Height(40)))
        {
            BuildrBuildingGenerator.Generate(data);
            editMode.UpdateRender(BuildrEditMode.renderModes.full);
        }
    }
示例#9
0
    public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize)
    {
        if (data.details.Count == 0)
        {
            return;
        }
        Undo.RecordObject(data, "Detail Modified");

        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   plan            = data.plan;
        int          numberOfVolumes = plan.numberOfVolumes;
        BuildrDetail bDetail         = data.details[selectedDetail];
        float        volumeHeight    = 0;
        Vector3      baseLeft        = Vector3.zero;
        Vector3      baseRight       = Vector3.zero;
        int          faceIndex       = bDetail.face;

        int facadeCounter = 0;

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

            for (int p = 0; p < volumeSize; p++)
            {
                int     point  = volume.points[p];
                int     indexB = volume.points[(p + 1) % volumeSize];
                Vector3 fb0    = plan.points[point].vector3;
                Vector3 fb1    = plan.points[indexB].vector3;
                if (bDetail.face == facadeCounter && bDetail.type == BuildrDetail.Types.Facade)
                {
                    baseLeft  = fb0;
                    baseRight = fb1;
                }
                floorCentre += baseLeft;

                List <Vector3> verts = new List <Vector3>();
                volumeHeight = (volume.numberOfFloors * data.floorHeight);
                Vector3 volumeHeightVector = Vector3.up * volumeHeight;
                verts.Add(fb0 + position);
                verts.Add(fb1 + position);
                verts.Add(verts[1] + volumeHeightVector);
                verts.Add(verts[0] + volumeHeightVector);
                if (bDetail.face == facadeCounter && bDetail.type == BuildrDetail.Types.Facade)
                {
                    //display something to highlight this facade
                    Handles.DrawSolidRectangleWithOutline(verts.ToArray(), Color.clear, BuildrColours.MAGENTA);
                }
                Handles.color = BuildrColours.CYAN;
                if (v == bDetail.face && bDetail.type == BuildrDetail.Types.Roof)
                {
                    Handles.DrawLine(verts[2], verts[3]);
                }
                if (editMode.showFacadeMarkers)
                {
                    Handles.color = Color.white;
                    Vector3  camDirection     = Camera.current.transform.forward;
                    Vector3  facadeDirection  = Vector3.Cross((verts[0] - verts[1]), Vector3.up);
                    GUIStyle facadeLabelStyle = new GUIStyle();
                    facadeLabelStyle.normal.textColor = Color.white;
                    facadeLabelStyle.alignment        = TextAnchor.MiddleCenter;
                    facadeLabelStyle.fixedWidth       = 75.0f;
                    if (Vector3.Dot(camDirection, facadeDirection) < 0)//only display label when facade is facing camera
                    {
                        Vector3 centerPos = (verts[0] + verts[1]) * 0.5f;
                        Vector3 labelPos  = centerPos + facadeDirection.normalized;
                        Handles.Label(labelPos, "facade " + facadeCounter, facadeLabelStyle);
                        Handles.DrawLine(centerPos, labelPos);
                    }
                }
                facadeCounter++;
            }
        }

        Vector3    handlePosition = bDetail.worldPosition + position;// new Vector3(basePos.x, volumeHeight * bDetail.faceUv.y, basePos.z);
        Vector3    baseDir        = (baseRight - baseLeft).normalized;
        Vector3    baseCross      = Vector3.Cross(Vector3.up, baseDir);
        Quaternion currentRot     = Quaternion.Euler(bDetail.userRotation);
        Quaternion faceRotation   = (bDetail.type == BuildrDetail.Types.Facade) ? Quaternion.LookRotation(baseCross) : Quaternion.identity;

        switch (Tools.current)
        {
        case Tool.Move:
            Vector3 dirX, dirY, dirZ;
            if (bDetail.type == BuildrDetail.Types.Facade)
            {
                dirX = baseDir;
                dirY = baseCross;
                dirZ = Vector3.up;
            }
            else
            {
                dirX = Vector3.right;
                dirY = Vector3.up;
                dirZ = Vector3.forward;
            }
            Vector3 newSliderPos;
            Handles.color = BuildrColours.RED;
            newSliderPos  = Handles.Slider(handlePosition, dirX, handleSize * 0.666f, Handles.ArrowCap, 0.0f);
            Handles.color = BuildrColours.BLUE;
            newSliderPos  = Handles.Slider(newSliderPos, dirZ, handleSize * 0.666f, Handles.ArrowCap, 0.0f);
            Handles.color = BuildrColours.GREEN;
            newSliderPos  = Handles.Slider(newSliderPos, dirY, handleSize * 0.666f, Handles.ArrowCap, 0.0f);
            Vector3 sliderDiff = newSliderPos - handlePosition;

            if (sliderDiff != Vector3.zero)
            {
                float newXUV = 0, newYUV = 0, newHeight = bDetail.faceHeight;
                if (bDetail.type == BuildrDetail.Types.Facade)
                {
                    float facadeWidth = Vector3.Distance(baseLeft, baseRight);
                    float sliderDiffX = Mathf.Sqrt(sliderDiff.x * sliderDiff.x + sliderDiff.z * sliderDiff.z) * Mathf.Sign(Vector3.Dot(baseDir, sliderDiff));
                    newXUV = sliderDiffX / facadeWidth + bDetail.faceUv.x;
                    newYUV = sliderDiff.y / volumeHeight + bDetail.faceUv.y;
                }
                else
                {
                    BuildrVolume volume = plan.volumes[faceIndex];
                    int          numberOfVolumePoints = volume.points.Count;
                    Vector3      minPoint             = plan.points[volume.points[0]].vector3;
                    Vector3      maxPoint             = plan.points[volume.points[0]].vector3;
                    for (int p = 1; p < numberOfVolumePoints; p++)
                    {
                        Vector3 fp0 = plan.points[volume.points[p]].vector3;
                        if (fp0.x < minPoint.x)
                        {
                            minPoint.x = fp0.x;
                        }
                        if (fp0.z < minPoint.z)
                        {
                            minPoint.z = fp0.z;
                        }
                        if (fp0.x > maxPoint.x)
                        {
                            maxPoint.x = fp0.x;
                        }
                        if (fp0.z > maxPoint.z)
                        {
                            maxPoint.z = fp0.z;
                        }
                    }
                    float roofWidth = maxPoint.x - minPoint.x;
                    float roofDepth = maxPoint.z - minPoint.z;
                    newXUV     = sliderDiff.x / roofWidth + bDetail.faceUv.x;
                    newYUV     = sliderDiff.z / roofDepth + bDetail.faceUv.y;
                    newHeight += sliderDiff.y;
                }
                bDetail.faceUv     = new Vector2(newXUV, newYUV);
                bDetail.faceHeight = newHeight;
            }
            break;

        case Tool.Rotate:
            currentRot           = Handles.RotationHandle(currentRot, handlePosition);
            bDetail.userRotation = currentRot.eulerAngles;
            break;

        case Tool.Scale:
            bDetail.scale = Handles.ScaleHandle(bDetail.scale, handlePosition, currentRot * faceRotation, handleSize * 0.666f);

            break;
        }

        //draw mesh bounds
        if (bDetail.mesh != null)
        {
            Bounds     meshBounds = bDetail.mesh.bounds;
            Quaternion rotation   = bDetail.worldRotation;
            Vector3    p0         = rotation * (new Vector3(meshBounds.min.x, meshBounds.min.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3    p1         = rotation * (new Vector3(meshBounds.max.x, meshBounds.min.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3    p2         = rotation * (new Vector3(meshBounds.min.x, meshBounds.min.y, meshBounds.max.z)) + bDetail.worldPosition;
            Vector3    p3         = rotation * (new Vector3(meshBounds.max.x, meshBounds.min.y, meshBounds.max.z)) + bDetail.worldPosition;
            Vector3    p4         = rotation * (new Vector3(meshBounds.min.x, meshBounds.max.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3    p5         = rotation * (new Vector3(meshBounds.max.x, meshBounds.max.y, meshBounds.min.z)) + bDetail.worldPosition;
            Vector3    p6         = rotation * (new Vector3(meshBounds.min.x, meshBounds.max.y, meshBounds.max.z)) + bDetail.worldPosition;
            Vector3    p7         = rotation * (new Vector3(meshBounds.max.x, meshBounds.max.y, meshBounds.max.z)) + bDetail.worldPosition;

            Handles.color = BuildrColours.BLUE;
            Handles.DrawLine(p0, p1);
            Handles.DrawLine(p0, p2);
            Handles.DrawLine(p1, p3);
            Handles.DrawLine(p2, p3);
            Handles.DrawLine(p0, p4);
            Handles.DrawLine(p1, p5);
            Handles.DrawLine(p2, p6);
            Handles.DrawLine(p3, p7);
            Handles.DrawLine(p4, p5);
            Handles.DrawLine(p4, p6);
            Handles.DrawLine(p5, p7);
            Handles.DrawLine(p6, p7);

            if (clickPlace)
            {
                Vector3 planeBase   = Vector3.zero;
                Vector3 planeNormal = Vector3.up;
                Vector3 planeSize   = Vector3.zero;
                if (bDetail.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 fp0    = plan.points[volume.points[indexA]].vector3;
                                Vector3 fp1    = plan.points[volume.points[indexB]].vector3;
                                planeBase   = fp0;
                                planeNormal = Vector3.Cross(Vector3.up, fp1 - fp0).normalized;
                                planeSize.x = Vector3.Distance(fp0, fp1);
                                planeSize.y = volume.numberOfFloors * data.floorHeight;
                                facadeFound = true;
                                break;
                            }
                            facadeCount++;
                        }
                        if (facadeFound)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    BuildrVolume volume = plan.volumes[faceIndex];
                    int          numberOfVolumePoints = volume.points.Count;
                    Vector3      minPoint             = plan.points[volume.points[0]].vector3;
                    Vector3      maxPoint             = plan.points[volume.points[0]].vector3;
                    for (int p = 1; p < numberOfVolumePoints; p++)
                    {
                        Vector3 fp0 = plan.points[volume.points[p]].vector3;
                        if (fp0.x < minPoint.x)
                        {
                            minPoint.x = fp0.x;
                        }
                        if (fp0.z < minPoint.z)
                        {
                            minPoint.z = fp0.z;
                        }
                        if (fp0.x > maxPoint.x)
                        {
                            maxPoint.x = fp0.x;
                        }
                        if (fp0.z > maxPoint.z)
                        {
                            maxPoint.z = fp0.z;
                        }
                    }
                    planeSize.x = maxPoint.x - minPoint.x;
                    planeSize.z = maxPoint.z - minPoint.z;
                    planeBase   = minPoint;
                    planeBase.y = (data.floorHeight * volume.numberOfFloors);
                }
                float distance;
                Plane buildingPlane = new Plane(planeNormal, planeBase);
                Ray   ray           = Camera.current.ScreenPointToRay(new Vector3(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 30, 0));
                if (buildingPlane.Raycast(ray, out distance))
                {
                    Vector3    mousePlanePoint    = ray.GetPoint(distance);
                    Quaternion mouseLookDirection = Quaternion.LookRotation(buildingPlane.normal);

                    if (Handles.Button(mousePlanePoint, mouseLookDirection, handleSize * 0.1f, handleSize * 0.1f, Handles.CircleCap))
                    {
                        float xUv, yUv;
                        if (bDetail.type == BuildrDetail.Types.Facade)
                        {
                            Vector3 facadeBaseMousePoint = new Vector3(mousePlanePoint.x, 0, mousePlanePoint.z);
                            xUv = Vector3.Distance(planeBase, facadeBaseMousePoint) / planeSize.x;
                            yUv = (mousePlanePoint.y - planeBase.y) / planeSize.y;
                        }
                        else
                        {
                            xUv = (mousePlanePoint.x - planeBase.x) / planeSize.x;
                            yUv = (mousePlanePoint.z - planeBase.z) / planeSize.z;
                        }
                        bDetail.faceUv = new Vector2(xUv, yUv);
                        clickPlace     = false;
                        GUI.changed    = true;
                    }
                }
            }
        }


        if (GUI.changed)
        {
            EditorUtility.SetDirty(editMode);
            EditorUtility.SetDirty(data);
            editMode.UpdateRender();
        }
    }
    public static void SceneGUI(BuildrEditMode editMode, BuildrPlan plan, bool shouldSnap, float handleSize)
    {
        Vector3 position = editMode.transform.position;
        Plane buildingPlane = new Plane(Vector3.up, position);
        float distance;
        Vector3 mousePlanePoint = Vector3.zero;
        Camera sceneCamera = Camera.current;
        Ray ray = sceneCamera.ScreenPointToRay(new Vector3(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 30, 0));
        if (buildingPlane.Raycast(ray, out distance))
        {
            mousePlanePoint = ray.GetPoint(distance);
        }
        Quaternion mouseLookDirection = Quaternion.LookRotation(-ray.direction);

        //Draw the floorplan outline
        int numberOfVolumes = plan.numberOfVolumes;
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volumeLinks = plan.volumes[s];
            int volumeSize = volumeLinks.Count;

            for (int l = 0; l < volumeSize; l++)
            {
                Handles.color = Color.white;
                Vector3[] wallPositions = plan.GetWallVectors(s, l);
                Handles.DrawLine(wallPositions[0] + position, wallPositions[1] + position);
            }
        }

        //draw outlines of building cores
        int numberOfCores = plan.cores.Count;
        for(int c = 0; c < numberOfCores; c++)
        {
            Rect coreOutline = plan.cores[c];
            Vector3 coreCenter = new Vector3(coreOutline.center.x,0,coreOutline.center.y);
            Handles.Label(coreCenter + position, "Core " + (c + 1));
            Vector3 coreBL = new Vector3(coreOutline.xMin,0, coreOutline.yMin) + position;
            Vector3 coreBR = new Vector3(coreOutline.xMax,0, coreOutline.yMin) + position;
            Vector3 coreTL = new Vector3(coreOutline.xMin,0, coreOutline.yMax) + position;
            Vector3 coreTR = new Vector3(coreOutline.xMax,0, coreOutline.yMax) + position;
            Handles.DrawLine(coreBL,coreBR);
            Handles.DrawLine(coreBR,coreTR);
            Handles.DrawLine(coreTR,coreTL);
            Handles.DrawLine(coreTL,coreBL);
        }

        //Draw red lines over illegal point/lines
        int numberOfIllegalPoints = plan.numberOfIllegalPoints;
        if (numberOfIllegalPoints > 0)
        {
            Handles.color = Color.red;
            Vector2z[] illegalPoints = plan.illegalPoints;
            for (int i = 0; i < numberOfIllegalPoints - 1; i += 2)
            {
                Vector3 a, b;
                a = illegalPoints[i].vector3 + position;
                b = illegalPoints[i + 1].vector3 + position;
                Handles.DrawLine(a, b);
            }
        }

        SceneView.focusedWindow.wantsMouseMove = false;
        Vector3 vertA;
        Vector3 vertB;
        int selectedPoint;
        switch (editMode.mode)
        {

            case BuildrEditMode.modes.floorplan:
                Vector3 sliderPos = Vector3.zero;
                int numberOfPoints = plan.points.Count;
                int numberOfSelectedPoints = editMode.selectedPoints.Count;

                //Per point scene gui
                for (int i = 0; i < numberOfPoints; i++)
                {
                    Vector2z point = plan.points[i];
                    Vector3 pointPos = point.vector3 + position;
                    float pointHandleSize = HandleUtility.GetHandleSize(pointPos);
                    bool selected = editMode.selectedPoints.Contains(i);
                    if (selected)
                    {
                        Handles.color = Color.green;
                        //Handles.Label(pointPos, "point "+i);
                        sliderPos += point.vector3;
                        if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                        {
                            editMode.selectedPoints.Remove(i);
                        }

                    }
                    else
                    {
                        Handles.color = Color.white;
                        if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.05f, pointHandleSize * 0.05f, Handles.DotCap))
                        {
                            if (!shouldSnap)
                                editMode.selectedPoints.Clear();
                            editMode.selectedPoints.Add(i);
                        }
                    }

                    float pointDot = Vector3.Dot(sceneCamera.transform.forward, pointPos - sceneCamera.transform.position);
                    if(pointDot > 0.0f)
                    {
                        Handles.color = Color.white;
                        GUIStyle pointLabelStyle = new GUIStyle();
                        pointLabelStyle.normal.textColor = Color.white;
                        pointLabelStyle.fontStyle = FontStyle.Bold;
                        pointLabelStyle.alignment = TextAnchor.MiddleCenter;
                        pointLabelStyle.fixedWidth = 50.0f;
                        Handles.Label(pointPos + Vector3.up * 2, "point " + i, pointLabelStyle);
                    }
                }

                //draw plan dimensions
                if (editMode.showDimensionLines)
                {
                    Handles.color = Color.white;
                    for (int v = 0; v < numberOfVolumes; v++)
                    {
                        BuildrVolume volume = plan.volumes[v];
                        int volumeSize = volume.Count;
                        for (int l = 0; l < volumeSize; l++)
                        {
                            if (plan.GetConnectingVolumeIndex(v, volume.points[l], volume.points[(l + 1) % volumeSize]) != -1)
                                continue;
                            vertA = plan.points[volume.points[l]].vector3 + position;
                            vertB = plan.points[volume.points[(l + 1) % volumeSize]].vector3 + position;
                            float wallWidth = Vector3.Distance(vertA, vertB);
                            Vector3 facadeDirection = Vector3.Cross((vertA - vertB), Vector3.up).normalized;
                            Vector3 labelPos = (vertA + vertB) * 0.5f + facadeDirection;
                            GUIStyle widthStyle = new GUIStyle();
                            widthStyle.normal.textColor = Color.white;
                            widthStyle.alignment = TextAnchor.MiddleCenter;
                            widthStyle.fixedWidth = 50.0f;
                            Handles.Label(labelPos, wallWidth.ToString("F2") + "m", widthStyle);
                            if (wallWidth > 3)//draw guidelines
                            {
                                float gapSpace = (HandleUtility.GetHandleSize(labelPos) * 0.5f) / wallWidth;
                                Vector3 lineStopA = Vector3.Lerp(vertA, vertB, (0.5f - gapSpace)) + facadeDirection;
                                Vector3 lineStopB = Vector3.Lerp(vertA, vertB, (0.5f + gapSpace)) + facadeDirection;
                                Handles.DrawLine(vertA + facadeDirection, lineStopA);
                                Handles.DrawLine(vertA + facadeDirection, vertA);
                                Handles.DrawLine(vertB + facadeDirection, lineStopB);
                                Handles.DrawLine(vertB + facadeDirection, vertB);
                            }
                        }
                    }
                }

                //selected point scene gui
                if (numberOfSelectedPoints > 0)
                {
        //                    Undo.SetSnapshotTarget(plan, "Floorplan Node Moved");
                    sliderPos /= numberOfSelectedPoints;
                    Vector3 dirX = (sliderPos.x < 0) ? Vector3.right : Vector3.left;
                    Vector3 dirZ = (sliderPos.z < 0) ? Vector3.forward : Vector3.back;
                    sliderPos += position;
                    Vector3 newSliderPos;
                    Handles.color = Color.red;
                    newSliderPos = Handles.Slider(sliderPos, dirX, HandleUtility.GetHandleSize(sliderPos) * 0.666f, Handles.ArrowCap, 0.0f);
                    Handles.color = Color.blue;
                    newSliderPos = Handles.Slider(newSliderPos, dirZ, HandleUtility.GetHandleSize(newSliderPos) * 0.666f, Handles.ArrowCap, 0.0f);

                    Vector3 sliderDiff = newSliderPos - sliderPos;

                    for (int i = 0; i < numberOfPoints; i++)
                    {
                        if (editMode.selectedPoints.Contains(i))
                        {
                            if(sliderDiff != Vector3.zero)
                            {
                                Vector2z point = plan.points[i];
                                point.vector3 += sliderDiff;

                                if(editMode.snapFloorplanToGrid)
                                {
                                    Vector3 snappedPoint = point.vector3;
                                    snappedPoint.x -= snappedPoint.x % editMode.floorplanGridSize;
                                    snappedPoint.z -= snappedPoint.z % editMode.floorplanGridSize;
                                    point.vector3 = snappedPoint;
                                }
                            }
                        }
                    }
                }

                //core gui
                for(int c = 0; c < numberOfCores; c++)
                {
        //                    Undo.SetSnapshotTarget(plan, "Core Node Moved");
                    Rect coreOutline = plan.cores[c];

                    Vector3 coreLeft = new Vector3(coreOutline.xMin, 0, (coreOutline.yMin + coreOutline.yMax)/2);
                    Vector3 coreRight = new Vector3(coreOutline.xMax, 0, (coreOutline.yMin + coreOutline.yMax)/2);
                    Vector3 coreBottom = new Vector3((coreOutline.xMin + coreOutline.xMax) / 2, 0, coreOutline.yMin);
                    Vector3 coreTop = new Vector3((coreOutline.xMin + coreOutline.xMax) / 2, 0, coreOutline.yMax);

                    Vector3 newCoreLeft = Handles.Slider(coreLeft + position, Vector3.left, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);
                    Vector3 newCoreRight = Handles.Slider(coreRight + position, Vector3.right, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);
                    Vector3 newCoreBottom = Handles.Slider(coreBottom + position, Vector3.back, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);
                    Vector3 newCoreTop = Handles.Slider(coreTop + position, Vector3.forward, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);

                    newCoreLeft -= position;
                    newCoreRight -= position;
                    newCoreBottom -= position;
                    newCoreTop -= position;

                    if (coreLeft != newCoreLeft)
                        coreOutline.xMin = Mathf.Min(newCoreLeft.x, coreOutline.xMax - 1.0f);
                    if (coreRight != newCoreRight)
                        coreOutline.xMax = Mathf.Max(newCoreRight.x, coreOutline.xMin + 1.0f);
                    if (coreBottom != newCoreBottom)
                        coreOutline.yMin = Mathf.Min(newCoreBottom.z, coreOutline.yMax - 1.0f);
                    if (coreTop != newCoreTop)
                        coreOutline.yMax = Mathf.Max(newCoreTop.z, coreOutline.yMin + 1.0f);

                    plan.cores[c] = coreOutline;
                }

                break;

            case BuildrEditMode.modes.addNewVolume:
                Vector3 basePoint = mousePlanePoint;
                Vector3 width = Vector3.right * 10;
                Vector3 height = Vector3.forward * 10;
                Vector3[] verts = new Vector3[4] { basePoint - width - height, basePoint + width - height, basePoint + width + height, basePoint + height - width };

                Handles.DrawSolidRectangleWithOutline(verts, new Color(0.2f, 0.4f, 0.9f, 0.5f), new Color(0.1f, 0.2f, 1.0f, 0.85f));
                Handles.Label(mousePlanePoint, "Click to place a new volume");
                if (Handles.Button(basePoint, Quaternion.identity, 0, 10, Handles.CircleCap))
                {
        //                    Undo.RegisterUndo(plan.GetUndoObjects(), "Add new volume");
                    plan.AddVolume(verts, -position);
                    editMode.SetMode(BuildrEditMode.modes.floorplan);
                    EditorUtility.SetDirty(plan);
                }

                break;

            case BuildrEditMode.modes.addNewVolumeByDraw:

                if (editMode.startVolumeDraw == Vector3.zero)
                {
                    Handles.Label(mousePlanePoint, "Click to select the start point of this volume");
                    if (Handles.Button(mousePlanePoint, Quaternion.identity, handleSize * 0.1f, handleSize * 0.1f, Handles.CircleCap))
                    {
                        editMode.startVolumeDraw = mousePlanePoint;
                    }
                }
                else
                {
                    Vector3 baseDrawPoint = editMode.startVolumeDraw;
                    Vector3 finishDrawPoint = mousePlanePoint;
                    Vector3[] drawVerts = new Vector3[4];
                    drawVerts[0] = new Vector3(baseDrawPoint.x, 0, baseDrawPoint.z);
                    drawVerts[1] = new Vector3(finishDrawPoint.x, 0, baseDrawPoint.z);
                    drawVerts[2] = new Vector3(finishDrawPoint.x, 0, finishDrawPoint.z);
                    drawVerts[3] = new Vector3(baseDrawPoint.x, 0, finishDrawPoint.z);

                    Handles.DrawSolidRectangleWithOutline(drawVerts, new Color(0.2f, 0.4f, 0.9f, 0.5f), new Color(0.1f, 0.2f, 1.0f, 0.85f));
                    Handles.Label(mousePlanePoint, "Click to finish and add a new volume");
                    if (Handles.Button(mousePlanePoint, Quaternion.identity, 0, 10, Handles.CircleCap))
                    {
        //                        Undo.RegisterUndo(plan.GetUndoObjects(), "Add new volume");
                        plan.AddVolume(drawVerts, -position);
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }
                }
                break;

            case BuildrEditMode.modes.addNewVolumeByPoints:

                int numberOfDrawnPoints = editMode.volumeDrawPoints.Count;
                bool allowNewPoint = true;
                for (int p = 0; p < numberOfDrawnPoints; p++)
                {
                    Vector3 point = editMode.volumeDrawPoints[p];
                    if (p == 0 && Vector3.Distance(point, mousePlanePoint) < 3 && numberOfDrawnPoints >= 3)
                    {
                        allowNewPoint = false;//hovering over the first point - don't add a new point - ready to complete the volume plan
                        Handles.color = Color.green;
                    }
                    Vector3 lookDirection = -(point - Camera.current.transform.position);

                    int p2 = (p + 1) % numberOfDrawnPoints;
                    if (p < numberOfDrawnPoints - 1 || !allowNewPoint)//don't draw last line
                        Handles.DrawLine(point, editMode.volumeDrawPoints[p2]);
                    float pointhandleSize = HandleUtility.GetHandleSize(point);
                    if (Handles.Button(point, Quaternion.LookRotation(lookDirection), pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                    {
                        if (p == 0 && numberOfDrawnPoints >= 3)
                        {
                            plan.AddVolume(editMode.volumeDrawPoints.ToArray(), -position);
                            editMode.SetMode(BuildrEditMode.modes.floorplan);
                            EditorUtility.SetDirty(plan);
                            GUI.changed = true;
                            return;
                        }
                    }
                }

                if (allowNewPoint)
                {

                    bool isLegal = true;
                    if (numberOfDrawnPoints >= 1)
                    {
                        Vector2z newPoint = new Vector2z(mousePlanePoint);
                        Vector2z lastPoint = new Vector2z(editMode.volumeDrawPoints[numberOfDrawnPoints - 1]);
                        for (int op = 0; op < numberOfDrawnPoints - 1; op++)//don't do the final line
                        {
                            int op2 = (op + 1) % numberOfDrawnPoints;

                            if (BuildrUtils.FastLineIntersection(newPoint, lastPoint, new Vector2z(editMode.volumeDrawPoints[op]), new Vector2z(editMode.volumeDrawPoints[op2])))
                                isLegal = false;
                        }
                        for (int v = 0; v < numberOfVolumes; v++)
                        {
                            BuildrVolume volume = plan.volumes[v];
                            int volumeSize = volume.Count;
                            for (int l = 0; l < volumeSize; l++)
                            {
                                int vp1 = l;
                                int vp2 = (l + 1) % volumeSize;

                                Vector2z v2zPos = new Vector2z(position);
                                Vector2z p1 = newPoint - v2zPos;
                                Vector2z p2 = lastPoint - v2zPos;
                                Vector2z p3 = plan.points[volume.points[vp1]];
                                Vector2z p4 = plan.points[volume.points[vp2]];

                                if (BuildrUtils.FastLineIntersection(p1, p2, p3, p4))
                                    isLegal = false;
                            }
                        }

                        Handles.Label(mousePlanePoint, "Click to add another point to the volume wall");

                        if (!isLegal)
                            Handles.color = Color.red;

                        Handles.DrawLine(lastPoint.vector3, newPoint.vector3);
                    }
                    else
                    {
                        Handles.Label(mousePlanePoint, "Click to add the first point in this volume wall");
                    }

                    Handles.color = Color.white;
                    if (Handles.Button(mousePlanePoint, mouseLookDirection, 0, 10, Handles.CircleCap))
                    {
                        if (isLegal)
                        {
        //                            Undo.RegisterUndo(plan.GetUndoObjects(), "Add new wall line for new volume");
                            editMode.volumeDrawPoints.Add(mousePlanePoint);
                            EditorUtility.SetDirty(plan);
                        }
                        else
                        {
                            EditorUtility.DisplayDialog("Error", "Wall lines cannot intersect other wall lines", "ok, sorry");
                        }
                    }
                }
                else
                {
                    Handles.Label(mousePlanePoint, "Click to complete the volume wall plan");
                }

                break;

            case BuildrEditMode.modes.removeVolume:

                for (int v = 0; v < numberOfVolumes; v++)
                {
                    BuildrVolume volume = plan.volumes[v];
                    int volumeSize = volume.Count;
                    Vector3 centerPoint = Vector3.zero;
                    for (int l = 0; l < volumeSize; l++)
                    {
                        centerPoint += plan.points[volume.points[l]].vector3;
                    }
                    centerPoint /= volumeSize;
                    centerPoint += position;

                    Handles.color = Color.red;
                    float centerPointHandleSize = HandleUtility.GetHandleSize(centerPoint);
                    if (Handles.Button(centerPoint, Quaternion.identity, centerPointHandleSize * 0.1f, centerPointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterUndo(plan.GetUndoObjects(), "Remove volume");
        //                        Undo.RegisterSceneUndo("Remove Volume");
                        plan.RemoveVolume(volume);
                        numberOfVolumes--;
                        v--;
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }
                }

                break;

            case BuildrEditMode.modes.mergeVolumes:

                List<int> usedPointsA = new List<int>();
                List<int> usedPointsB = new List<int>();
                for (int v = 0; v < numberOfVolumes; v++)
                {
                    BuildrVolume volume = plan.volumes[v];
                    int volumeSize = volume.Count;
                    for (int p = 0; p < volumeSize; p++)
                    {
                        int a = volume.points[p];
                        int b = volume.points[(p + 1) % volumeSize];

                        bool alreadyDrawn = false;
                        foreach (int pa in usedPointsA)
                        {
                            if (pa == a || pa == b)
                            {
                                int pb = usedPointsB[usedPointsA.IndexOf(pa)];
                                if (pb == a || pb == b)
                                {
                                    alreadyDrawn = true;
                                    break;
                                }
                            }
                        }

                        if (!alreadyDrawn)
                        {

                            usedPointsA.Add(a);
                            usedPointsA.Add(b);
                            usedPointsB.Add(b);
                            usedPointsB.Add(a);

                            int otherV = plan.GetConnectingVolumeIndex(v, a, b);
                            if (otherV == -1)
                                continue;//it's not connected to another volume

                            vertA = plan.points[a].vector3 + position;
                            vertB = plan.points[b].vector3 + position;
                            Vector3 diff = vertA - vertB;
                            Vector3 facadeDirection = Vector3.Cross(diff, Vector3.up).normalized;
                            Vector3 midPoint = Vector3.Lerp(vertA, vertB, 0.5f);

                            float mergeHandleSize = HandleUtility.GetHandleSize(midPoint) * 0.1f;
                            Vector3 outPointA = midPoint + (facadeDirection * mergeHandleSize * 6);
                            Vector3 outPointB = midPoint - (facadeDirection * mergeHandleSize * 6);
                            Handles.ArrowCap(0, outPointA, Quaternion.LookRotation(-facadeDirection), mergeHandleSize * 4);
                            Handles.ArrowCap(0, outPointB, Quaternion.LookRotation(facadeDirection), mergeHandleSize * 4);

                            GUIStyle pointLabelStyle = new GUIStyle();
                            pointLabelStyle.normal.textColor = Color.white;
                            pointLabelStyle.fontStyle = FontStyle.Bold;
                            pointLabelStyle.alignment = TextAnchor.MiddleCenter;
                            pointLabelStyle.fixedWidth = 50.0f;
                            Handles.Label(midPoint + Vector3.up * mergeHandleSize * 3, "Merge", pointLabelStyle);

                            if (Handles.Button(midPoint, Quaternion.identity, mergeHandleSize, mergeHandleSize, Handles.DotCap))
                            {
        //                                Undo.RegisterSceneUndo("Merge Volume");
                                int otherVolume = plan.GetConnectingVolumeIndex(v, a, b);
                                plan.MergeVolumes(v, otherVolume);
                                numberOfVolumes--;
                                editMode.SetMode(BuildrEditMode.modes.floorplan);
                                EditorUtility.SetDirty(plan);
                            }
                        }
                    }
                }

                break;

            //SUB VOLUME FUNCTIONS

            case BuildrEditMode.modes.splitwall:

                SceneView.focusedWindow.wantsMouseMove = true;
                float pointDistance = 999;
                int wallIndex = -1;
                int volumeIndex = -1;
                Vector3 closestPoint = Vector3.zero;
                Vector3 usePoint = Vector3.zero;
                vertA = Vector3.zero;
                vertB = Vector3.zero;

                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volumeLinks = plan.volumes[s];
                    int volumeSize = volumeLinks.Count;

                    for (int l = 0; l < volumeSize; l++)
                    {
                        Vector3[] wallVectors = plan.GetWallVectors(s, l);
                        closestPoint = BuildrUtils.ClosestPointOnLine(wallVectors[0] + position, wallVectors[1] + position, mousePlanePoint);
                        float thisDist = Vector3.Distance(closestPoint, mousePlanePoint);
                        if (thisDist < pointDistance)
                        {
                            wallIndex = l;
                            volumeIndex = s;
                            vertA = wallVectors[0];
                            vertB = wallVectors[1];
                            usePoint = closestPoint;
                            pointDistance = thisDist;
                            editMode.selectedPoints.Clear();
                        }

                        Handles.color = Color.white;
                        float wallHandleSize = HandleUtility.GetHandleSize(wallVectors[0] + position);
                        Handles.DotCap(0, wallVectors[0] + position, Quaternion.identity, wallHandleSize * 0.05f);
                    }
                }

                if (wallIndex != -1 && pointDistance < 5 && volumeIndex != -1)
                {
                    float pointHandleSize = HandleUtility.GetHandleSize(usePoint);
                    if (Handles.Button(usePoint, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterUndo(plan.GetUndoObjects(), "Split Wall");
                        int newPointID = plan.AddWallPoint(usePoint - position, wallIndex, volumeIndex);
                        editMode.selectedPoints.Clear();
                        editMode.selectedPoints.Add(newPointID);
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }

                    Handles.color = Color.white;
                    GUIStyle widthStyle = new GUIStyle();
                    widthStyle.normal.textColor = Color.white;
                    widthStyle.alignment = TextAnchor.MiddleCenter;
                    widthStyle.fixedWidth = 50.0f;
                    Vector3 facadeDirection = Vector3.Cross((vertA - vertB), Vector3.up).normalized;

                    float wallWidthA = Vector3.Distance(vertA, usePoint);
                    Vector3 labelPosA = (vertA + usePoint) * 0.5f + facadeDirection;
                    Handles.Label(labelPosA, wallWidthA.ToString("F2") + "m", widthStyle);
                    if (wallWidthA > 3)//draw guidelines
                    {
                        float gapSpace = (pointHandleSize * 0.5f) / wallWidthA;
                        Vector3 lineStopA = Vector3.Lerp(vertA, usePoint, (0.5f - gapSpace)) + facadeDirection;
                        Vector3 lineStopB = Vector3.Lerp(vertA, usePoint, (0.5f + gapSpace)) + facadeDirection;
                        Handles.DrawLine(vertA + facadeDirection, lineStopA);
                        Handles.DrawLine(vertA + facadeDirection, vertA);
                        Handles.DrawLine(usePoint + facadeDirection, lineStopB);
                        Handles.DrawLine(usePoint + facadeDirection, usePoint);
                    }

                    float wallWidthB = Vector3.Distance(usePoint, vertB);
                    Vector3 labelPosB = (usePoint + vertB) * 0.5f + facadeDirection;
                    Handles.Label(labelPosB, wallWidthB.ToString("F2") + "m", widthStyle);
                    if (wallWidthB > 3)//draw guidelines
                    {
                        float gapSpace = (pointHandleSize * 0.5f) / wallWidthB;
                        Vector3 lineStopA = Vector3.Lerp(vertB, usePoint, (0.5f - gapSpace)) + facadeDirection;
                        Vector3 lineStopB = Vector3.Lerp(vertB, usePoint, (0.5f + gapSpace)) + facadeDirection;
                        Handles.DrawLine(vertB + facadeDirection, lineStopA);
                        Handles.DrawLine(vertB + facadeDirection, vertB);
                        Handles.DrawLine(usePoint + facadeDirection, lineStopB);
                        Handles.DrawLine(usePoint + facadeDirection, usePoint);
                    }
                }
                Handles.color = Color.white;
                break;

            case BuildrEditMode.modes.removewall:

                int index = 0;
                foreach (Vector2z point in plan.points)
                {
                    Handles.color = Color.white;
                    Vector3 pointPos = point.vector3 + position;
                    float pointHandleSize = HandleUtility.GetHandleSize(pointPos);
                    if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterSceneUndo("Delete Wall Point");
                        plan.RemovePoint(index);
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        break;
                    }

                    index++;
                }

                break;

            case BuildrEditMode.modes.extrudewallselect:

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

                    for (int l = 0; l < volumeSize; l++)
                    {
                        int a = volume.points[l];
                        int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0];
                        if (plan.GetConnectingVolumeIndex(s, a, b) == -1)//if the volume wall has not been connected to two volumes yet...
                        {
                            Vector3[] pIndexes = plan.GetWallVectors(s, l);
                            Vector3 pA = pIndexes[0];
                            Vector3 pB = pIndexes[1];
                            Vector3 pC = (pA + pB) / 2 + position;
                            float pointHandleSize = HandleUtility.GetHandleSize(pC);

                            if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                            {
        //                                Undo.RegisterSceneUndo("Extrude wall");
                                int wallIndexA = l;
                                int newPointAIndex = plan.AddWallPoint(pA, wallIndexA, s);
                                int wallIndexB = l + 1;

                                int newPointBIndex = plan.AddWallPoint(pB, wallIndexB, s);

                                editMode.SetMode(BuildrEditMode.modes.floorplan);

                                editMode.selectedPoints.Clear();
                                editMode.selectedPoints.Add(newPointAIndex);
                                editMode.selectedPoints.Add(newPointBIndex);
                                break;
                            }
                        }
                    }
                }

                Handles.color = Color.white;

                break;

            case BuildrEditMode.modes.addVolumeByPoint:

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

                    for (int l = 0; l < volumeSize; l++)
                    {
                        int a = volume.points[l];
                        int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0];
                        if (plan.GetConnectingVolumeIndex(s, a, b) == -1)//if the volume wall has not been connected to two volumes yet...
                        {
                            Vector3[] pointVectors = plan.GetWallVectors(s, l);
                            Vector3 pA = pointVectors[0];
                            Vector3 pB = pointVectors[1];
                            Vector3 pC = (pA + pB) / 2 + position;
                            float pointHandleSize = HandleUtility.GetHandleSize(pC);
                            if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                            {
                                Vector2z[] newPoints = new Vector2z[1];
                                float pointDist = Vector3.Distance(pA, pB);
                                Vector3 newPointPos = Vector3.Cross(pA - pB, Vector3.up).normalized * pointDist;
                                newPoints[0] = new Vector2z(pC + newPointPos);
                                int indexa, indexb;
                                indexa = volume.points[l];
                                if (l < volumeSize - 1)
                                    indexb = volume.points[l + 1];
                                else
                                    indexb = volume.points[0];
                                plan.AddVolume(indexa, indexb, newPoints);

                                editMode.SetMode(BuildrEditMode.modes.floorplan);
                                break;
                            }
                        }
                    }
                }
                Handles.color = Color.white;
                break;

            case BuildrEditMode.modes.addVolumeByWall:

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

                    for (int l = 0; l < volumeSize; l++)
                    {
                        int a = volume.points[l];
                        int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0];
                        if (plan.GetConnectingVolumeIndex(s, a, b) == -1)
                        {
                            Vector3[] pIndexes = plan.GetWallVectors(s, l);
                            Vector3 pA = pIndexes[0];
                            Vector3 pB = pIndexes[1];
                            Vector3 pC = (pA + pB) / 2 + position;
                            float pointHandleSize = HandleUtility.GetHandleSize(pC);
                            if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                            {
        //                                Undo.RegisterSceneUndo("Add volume by wall");
                                Vector2z[] newPoints = new Vector2z[2];
                                float pointDist = Vector3.Distance(pA, pB);
                                Vector3 newPointPos = Vector3.Cross(pA - pB, Vector3.up).normalized * pointDist;
                                newPoints[0] = new Vector2z(pA + newPointPos);
                                newPoints[1] = new Vector2z(pB + newPointPos);
                                int indexa, indexb;
                                indexa = volume.points[l];
                                if (l < volumeSize - 1)
                                    indexb = volume.points[l + 1];
                                else
                                    indexb = volume.points[0];
                                plan.AddVolume(indexa, indexb, newPoints);

                                editMode.SetMode(BuildrEditMode.modes.floorplan);
                                break;
                            }
                        }
                    }
                }
                Handles.color = Color.white;
                break;

            case BuildrEditMode.modes.addPointToVolume:

                numberOfPoints = plan.numberOfPoints;
                if (editMode.selectedPoint == -1)
                {
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        Vector2z point = plan.points[p];
                        Handles.color = Color.white;
                        Vector3 pointPos = point.vector3 + position;
                        float pointhandleSize = HandleUtility.GetHandleSize(pointPos);
                        if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                        {
        //                            Undo.RegisterSceneUndo("Select Wall Point");
                            editMode.selectedPoint = p;
                            break;
                        }
                    }
                }
                else
                {

                    selectedPoint = editMode.selectedPoint;
                    Vector2z startPoint = plan.points[selectedPoint];
                    Vector2z endPoint = new Vector2z(mousePlanePoint - position);

                    bool isLegal = true;
                    for (int s = 0; s < numberOfVolumes; s++)
                    {
                        BuildrVolume volume = plan.volumes[s];
                        if (!volume.Contains(selectedPoint))
                            continue;
                        int volumeSize = volume.Count;

                        for (int l = 0; l < volumeSize; l++)
                        {
                            int a = volume.points[l];
                            int b = volume.points[(l + 1) % volumeSize];

                            if (a == selectedPoint || b == selectedPoint)
                                continue;

                            if (BuildrUtils.FastLineIntersection(startPoint, endPoint, plan.points[a], plan.points[b]))
                                isLegal = false;
                        }
                    }

                    Handles.color = isLegal ? Color.white : Color.red;
                    Handles.DrawLine(startPoint.vector3 + position, endPoint.vector3 + position);

                }

                break;

            case BuildrEditMode.modes.splitVolume:

                numberOfPoints = plan.numberOfPoints;
                selectedPoint = editMode.selectedPoint;
                if (selectedPoint == -1)
                {
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        Vector2z point = plan.points[p];
                        Handles.color = Color.white;
                        Vector3 pointPos = point.vector3 + position;
                        float pointhandleSize = HandleUtility.GetHandleSize(pointPos);

                        if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                        {
        //                            Undo.RegisterSceneUndo("Select Wall Point");
                            editMode.selectedPoint = p;
                            break;
                        }
                    }
                }
                else
                {

                    for (int s = 0; s < numberOfVolumes; s++)
                    {
                        BuildrVolume volume = plan.volumes[s];
                        if (!volume.Contains(selectedPoint))
                            continue;
                        int volumeSize = volume.Count;

                        for (int l = 0; l < volumeSize; l++)
                        {

                            int o = volume.points[l];
                            int a = selectedPoint;
                            int selectedVolumePoint = volume.IndexOf(selectedPoint);
                            int b = volume.points[(selectedVolumePoint + 1) % volumeSize];
                            int volb = (selectedVolumePoint - 1) % volumeSize;
                            if (volb == -1) volb = volumeSize - 1;
                            int c = volume.points[volb];

                            if (o == a || o == b || o == c)
                                continue;

                            Vector3 pointPos = plan.points[o].vector3 + position;

                            bool isLegal = true;
                            for (int j = 0; j < volumeSize; j++)
                            {
                                int ob = volume.points[j];
                                int oc = volume.points[(j + 1) % volumeSize];
                                if (ob == selectedPoint || oc == selectedPoint || ob == o || oc == o)
                                    continue;
                                if (BuildrUtils.FastLineIntersection(plan.points[selectedPoint], plan.points[o], plan.points[ob], plan.points[oc]))
                                    isLegal = false;
                            }

                            Vector2z pA = plan.points[a];
                            Vector2z pB = plan.points[b];
                            Vector2z pC = plan.points[c];
                            Vector2z pO = plan.points[o];

                            float startAng, endAng, mouseAng, ang;
                            Vector3 cross;
                            Vector2z diff;

                            diff = pC - pA;
                            ang = Vector2.Angle(Vector2.up, diff.vector2);
                            cross = Vector3.Cross(Vector3.forward, diff.vector3);
                            startAng = (cross.y > 0) ? ang : 360 - ang;

                            diff = pB - pA;
                            ang = Vector2.Angle(Vector2.up, diff.vector2);
                            cross = Vector3.Cross(Vector3.forward, diff.vector3);
                            endAng = (cross.y > 0) ? ang : 360 - ang;

                            diff = pO - pA;
                            ang = Vector2.Angle(Vector2.up, diff.vector2);
                            cross = Vector3.Cross(Vector3.forward, diff.vector3);
                            mouseAng = (cross.y > 0) ? ang : 360 - ang;

                            mouseAng = (360 + (mouseAng % 360)) % 360;
                            startAng = (3600000 + startAng) % 360;
                            endAng = (3600000 + endAng) % 360;

                            bool isBetween = false;
                            if (startAng < endAng)
                                isBetween = startAng <= mouseAng && mouseAng <= endAng;
                            else
                                isBetween = startAng <= mouseAng || mouseAng <= endAng;

                            if (isLegal && !isBetween)
                                isLegal = false;

                            if (isLegal)
                            {
                                Handles.color = Color.white;
                                float pointhandleSize = HandleUtility.GetHandleSize(pointPos);
                                if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                                {
        //                                    Undo.RegisterSceneUndo("Split Volume");
                                    plan.SplitVolume(s, a, o);
                                    editMode.selectedPoint = -1;
                                    editMode.SetMode(BuildrEditMode.modes.floorplan);
                                    return;
                                }
                                Handles.color = new Color(1, 0, 0, 0.25f);
                                Handles.DrawLine(plan.points[selectedPoint].vector3 + position, plan.points[o].vector3 + position);
                            }
                        }
                    }
                }

                break;

                case BuildrEditMode.modes.addNewCore:

                SceneView.focusedWindow.wantsMouseMove = true;
                Vector3 coreBasePoint = mousePlanePoint;
                Vector3 coreWidth = Vector3.right * 2.5f;
                Vector3 coreHeight = Vector3.forward * 2.5f;
                Vector3[] coreVerts = new Vector3[4] { coreBasePoint - coreWidth - coreHeight, coreBasePoint + coreWidth - coreHeight, coreBasePoint + coreWidth + coreHeight, coreBasePoint + coreHeight - coreWidth };

                Color newCoreColour = BuildrColours.RED;
                newCoreColour.a = 0.5f;
                Handles.DrawSolidRectangleWithOutline(coreVerts, newCoreColour, BuildrColours.YELLOW);
                Handles.Label(mousePlanePoint, "Click to place a new core");
                if (Handles.Button(coreBasePoint, Quaternion.identity, 0, 10, Handles.CircleCap))
                {
        //                    Undo.RegisterSceneUndo("Add new core");
                    Vector3 coreBase = coreBasePoint - position;
                    Rect newCoreRect = new Rect(coreBase.x - 2.5f, coreBase.z - 2.5f, 5.0f, 5.0f);
                    plan.cores.Add(newCoreRect);
                    editMode.SetMode(BuildrEditMode.modes.floorplan);
                    EditorUtility.SetDirty(plan);
                }

                break;

                case BuildrEditMode.modes.removeCore:

                for (int c = 0; c < numberOfCores; c++)
                {
                    Rect core = plan.cores[c];
                    Vector3 centerPoint = new Vector3(core.center.x, 0, core.center.y) + position;

                    Handles.color = Color.red;
                    float centerPointHandleSize = HandleUtility.GetHandleSize(centerPoint);
                    if (Handles.Button(centerPoint, Quaternion.identity, centerPointHandleSize * 0.1f, centerPointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterSceneUndo("Remove Core");
                        plan.cores.RemoveAt(c);
                        numberOfCores--;
                        c--;
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }
                }

                break;
        }

        bool clickedOutside = false;
        if (Event.current.isMouse)
        {
            RaycastHit hitInfo;
            clickedOutside = true;
            if (Physics.Raycast(ray, out hitInfo))
            {
                if (hitInfo.collider.gameObject == editMode.gameObject)
                    clickedOutside = false;
            }
        }

        if (clickedOutside)
            editMode.selectedPoints.Clear();

        if (GUI.changed)
        {
            plan.CheckPlan();
            EditorUtility.SetDirty(editMode);
            EditorUtility.SetDirty(plan);
            editMode.UpdateRender();
        }
    }