public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize) { if (GUI.changed) { EditorUtility.SetDirty(editMode); EditorUtility.SetDirty(data); editMode.UpdateRender(); } }
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(); } }
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); }
//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 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); } }
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(); } }