using System.Collections.Generic; using UnityEngine; using UnityEditor; using UnityEditor.SceneManagement; using RayFire; namespace RayFireEditor { [CanEditMultipleObjects] [CustomEditor (typeof(RayfireConnectivity))] public class RayfireConnectivityEditor : Editor { RayfireConnectivity conn; static readonly Color stressColor = Color.green; // Foldout static bool fld_filters; static bool fld_props_clp; static bool fld_props_str; static bool fld_joints; // Minimum & Maximum ranges const float expand_min = 0; const float expand_max = 1f; const float minimumArea_min = 0; const float minimumArea_max = 1f; const float minimumSize_min = 0; const float minimumSize_max = 10f; const int percentage_min = 0; const int percentage_max = 100; const int seed_min = 0; const int seed_max = 100; const int sub_thr_min = 10; const int sub_thr_max = 999; const int sub_cls_min = 2; const int sub_cls_max = 99; const int sub_deb_min = 0; const int sub_deb_max = 60; const int integrity_min = 1; const int integrity_max = 99; const int start_min = 0; const int start_max = 99; const int end_min = 1; const int end_max = 100; const int steps_min = 1; const int steps_max = 100; const float duration_min = 0; const float duration_max = 60f; const int var_min = 0; const int var_max = 100; const int seed_clp_min = 0; const int seed_clp_max = 99; const int threshold_min = 1; const int threshold_max = 1000; const float erosion_min = 0; const float erosion_max = 10f; const float interval_min = 0.1f; const float interval_max = 10f; const int support_min = 0; const int support_max = 90; const int debris_min = 0; const int debris_max = 50; // Connectivity Serialized properties SerializedProperty sp_show_giz; SerializedProperty sp_show_con; SerializedProperty sp_show_nod; SerializedProperty sp_type; SerializedProperty sp_expand; SerializedProperty sp_minimumArea; SerializedProperty sp_minimumSize; SerializedProperty sp_percentage; SerializedProperty sp_seed; SerializedProperty sp_clusterize; SerializedProperty sp_sub_enable; SerializedProperty sp_sub_thr; SerializedProperty sp_sub_min; SerializedProperty sp_sub_max; SerializedProperty sp_sub_deb; SerializedProperty sp_demolishable; SerializedProperty sp_triggerCollider; SerializedProperty sp_triggerDebris; // Collapse Serialized properties SerializedProperty sp_startCollapse; SerializedProperty sp_clp_integrity; SerializedProperty sp_clp_type; SerializedProperty sp_start; SerializedProperty sp_end; SerializedProperty sp_steps; SerializedProperty sp_duration; SerializedProperty sp_var; SerializedProperty sp_clp_seed; // Stress Serialized properties SerializedProperty sp_showStress; SerializedProperty sp_startStress; SerializedProperty sp_str_integrity; SerializedProperty sp_enable; SerializedProperty sp_threshold; SerializedProperty sp_erosion; SerializedProperty sp_interval; SerializedProperty sp_support; SerializedProperty sp_exposed; SerializedProperty sp_bySize; void OnEnable() { // Get component conn = (RayfireConnectivity)target; // Find Connectivity properties sp_show_giz = serializedObject.FindProperty(nameof(conn.showGizmo)); sp_show_con = serializedObject.FindProperty(nameof(conn.showConnections)); sp_show_nod = serializedObject.FindProperty(nameof(conn.showNodes)); sp_type = serializedObject.FindProperty(nameof(conn.type)); sp_expand = serializedObject.FindProperty(nameof(conn.expand)); sp_minimumArea = serializedObject.FindProperty(nameof(conn.minimumArea)); sp_minimumSize = serializedObject.FindProperty(nameof(conn.minimumSize)); sp_percentage = serializedObject.FindProperty(nameof(conn.percentage)); sp_seed = serializedObject.FindProperty(nameof(conn.seed)); sp_clusterize = serializedObject.FindProperty(nameof(conn.clusterize)); sp_sub_enable = serializedObject.FindProperty(nameof(conn.subEnable)); sp_sub_thr = serializedObject.FindProperty(nameof(conn.subThr)); sp_sub_min = serializedObject.FindProperty(nameof(conn.subMin)); sp_sub_max = serializedObject.FindProperty(nameof(conn.subMax)); sp_sub_deb = serializedObject.FindProperty(nameof(conn.subDeb)); sp_demolishable = serializedObject.FindProperty(nameof(conn.demolishable)); sp_triggerCollider = serializedObject.FindProperty(nameof(conn.triggerCollider)); sp_triggerDebris = serializedObject.FindProperty(nameof(conn.triggerDebris)); // Find Collapse properties sp_startCollapse = serializedObject.FindProperty(nameof(conn.startCollapse)); sp_clp_integrity = serializedObject.FindProperty(nameof(conn.collapseByIntegrity)); sp_clp_type = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.type)); sp_start = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.start)); sp_end = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.end)); sp_steps = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.steps)); sp_duration = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.duration)); sp_var = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.var)); sp_clp_seed = serializedObject.FindProperty(nameof(conn.collapse) + "." + nameof(conn.collapse.seed)); // Find Stress properties sp_showStress = serializedObject.FindProperty(nameof(conn.showStress)); sp_startStress = serializedObject.FindProperty(nameof(conn.startStress)); sp_str_integrity = serializedObject.FindProperty(nameof(conn.stressByIntegrity)); sp_enable = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.enable)); sp_threshold = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.threshold)); sp_erosion = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.erosion)); sp_interval = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.interval)); sp_support = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.support)); sp_exposed = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.exposed)); sp_bySize = serializedObject.FindProperty(nameof(conn.stress) + "." + nameof(conn.stress.bySize)); // Foldouts if (EditorPrefs.HasKey (TextKeys.con_fld_flt) == true) fld_filters = EditorPrefs.GetBool (TextKeys.con_fld_flt); if (EditorPrefs.HasKey (TextKeys.con_fld_clp) == true) fld_props_clp = EditorPrefs.GetBool (TextKeys.con_fld_clp); if (EditorPrefs.HasKey (TextKeys.con_fld_str) == true) fld_props_str = EditorPrefs.GetBool (TextKeys.con_fld_str); if (EditorPrefs.HasKey (TextKeys.con_fld_jnt) == true) fld_joints = EditorPrefs.GetBool (TextKeys.con_fld_jnt); } /// ///////////////////////////////////////////////////////// /// Inspector /// ///////////////////////////////////////////////////////// public override void OnInspectorGUI() { // Update changed properties serializedObject.Update(); GUI_Preview(); GUI_Info(); GUI_Connectivity(); if (conn.joints.enable == false) { GUI_Cluster(); GUI_Collapse(); GUI_Stress(); GUI_Trigger(); } // TODO update UI_Joints(); // Apply changes serializedObject.ApplyModifiedProperties(); } /// ///////////////////////////////////////////////////////// /// Top /// ///////////////////////////////////////////////////////// void GUI_Preview() { EditorGUI.BeginChangeCheck(); GUICommon.Toggle (sp_show_giz, TextCnt.gui_btn_gizmo); EditorGUILayout.BeginHorizontal(); GUICommon.Toggle (sp_show_con, TextCnt.gui_btn_cnt); GUICommon.Toggle (sp_show_nod,TextCnt.gui_btn_nodes); EditorGUILayout.EndHorizontal(); if (EditorGUI.EndChangeCheck()) SceneView.RepaintAll(); } void GUI_Info() { if (conn.cluster.shards.Count > 0) { GUICommon.Space(); GUILayout.Label (TextCnt.str_setup, EditorStyles.boldLabel); GUICommon.Space(); GUILayout.Label (TextCnt.str_shards + conn.cluster.shards.Count + "/" + conn.initShardAmount); GUICommon.Space (); GUILayout.Label (TextCnt.str_amount + conn.AmountIntegrity + "%"); GUICommon.Space (); } } /// ///////////////////////////////////////////////////////// /// Connectivity /// ///////////////////////////////////////////////////////// void GUI_Connectivity () { GUICommon.CaptionBox (TextCnt.gui_cap_conn); GUICommon.PropertyField (sp_type, TextCnt.gui_type); if (conn.type != ConnectivityType.ByTriangles && conn.type != ConnectivityType.ByPolygons) GUICommon.Slider (sp_expand, expand_min, expand_max, TextCnt.gui_expand); GUICommon.Foldout (ref fld_filters, TextKeys.con_fld_flt, TextCnt.gui_fld_filters.text); if (fld_filters == true) { EditorGUI.indentLevel++; if (conn.type != ConnectivityType.ByBoundingBox) GUICommon.Slider (sp_minimumArea, minimumArea_min, minimumArea_max, TextCnt.gui_minimumArea); GUICommon.Slider (sp_minimumSize, minimumSize_min, minimumSize_max, TextCnt.gui_minimumSize); GUICommon.IntSlider (sp_percentage, percentage_min, percentage_max, TextCnt.gui_percentage); if (conn.percentage > 0) GUICommon.IntSlider (sp_seed, seed_min, seed_max, TextCnt.gui_seed); EditorGUI.indentLevel--; } } /// ///////////////////////////////////////////////////////// /// Cluster /// ///////////////////////////////////////////////////////// void GUI_Cluster() { GUICommon.CaptionBox (TextCnt.gui_cap_cluster); GUICommon.PropertyField (sp_clusterize, TextCnt.gui_clusterize); if (conn.clusterize == true) { GUICommon.PropertyField (sp_sub_enable, TextCnt.gui_sub_enable); if (conn.subEnable == true) { EditorGUI.indentLevel++; GUICommon.IntSlider (sp_sub_thr, sub_thr_min, sub_thr_max, TextCnt.gui_sub_thr); GUICommon.IntSlider (sp_sub_min, sub_cls_min, sub_cls_max, TextCnt.gui_sub_min); GUICommon.IntSlider (sp_sub_max, sub_cls_min, sub_cls_max, TextCnt.gui_sub_max); GUICommon.IntSlider (sp_sub_deb, sub_deb_min, sub_deb_max, TextCnt.gui_sub_deb); EditorGUI.indentLevel--; } GUICommon.PropertyField (sp_demolishable, TextCnt.gui_demolishable); } } /// ///////////////////////////////////////////////////////// /// Collapse /// ///////////////////////////////////////////////////////// void GUI_Collapse() { GUICommon.CaptionBox (TextCnt.gui_cap_collapse); GUICommon.PropertyField (sp_startCollapse, TextCnt.gui_startCollapse); if (conn.startCollapse == RayfireConnectivity.RFConnInitType.ByIntegrity) GUICommon.IntSlider (sp_clp_integrity, integrity_min, integrity_max, TextCnt.gui_integrity); GUICommon.Foldout (ref fld_props_clp, TextKeys.con_fld_clp, TextCnt.gui_fld_props.text); if (fld_props_clp == true) { EditorGUI.indentLevel++; GUICommon.PropertyField (sp_clp_type, TextClp.gui_type); GUICommon.IntSlider (sp_start, start_min, start_max, TextClp.gui_start); GUICommon.IntSlider (sp_end, end_min, end_max, TextClp.gui_end); GUICommon.IntSlider (sp_steps, steps_min, steps_max, TextClp.gui_steps); GUICommon.Slider (sp_duration, duration_min, duration_max, TextClp.gui_duration); if (conn.collapse.type != RFCollapse.RFCollapseType.Random) GUICommon.IntSlider (sp_var, var_min, var_max, TextClp.gui_var); GUICommon.IntSlider (sp_clp_seed, seed_clp_min, seed_clp_max, TextClp.gui_seed); EditorGUI.indentLevel--; } GUI_Collapse_Buttons(); GUI_Collapse_Sliders(); } void GUI_Collapse_Buttons() { // Only runtime if (Application.isPlaying == false) return; GUICommon.Space (); // Show start collapse if not Start by default if (conn.collapse.inProgress == false) { if (GUILayout.Button (TextCnt.gui_btn_clp_start, GUILayout.Height (25))) foreach (var targ in targets) if (targ as RayfireConnectivity != null) RFCollapse.StartCollapse (targ as RayfireConnectivity); } // Show stop collapse if not Start by default if (conn.collapse.inProgress == true) { if (GUILayout.Button (TextCnt.gui_btn_clp_stop, GUILayout.Height (25))) foreach (var targ in targets) if (targ as RayfireConnectivity != null) RFCollapse.StopCollapse (targ as RayfireConnectivity); } } void GUI_Collapse_Sliders() { // Only runtime if (Application.isPlaying == false) return; GUICommon.Space (); GUILayout.BeginHorizontal(); GUILayout.Label (TextClp.str_area, GUILayout.Width (55)); // Start check for slider change EditorGUI.BeginChangeCheck(); conn.cluster.areaCollapse = EditorGUILayout.Slider(conn.cluster.areaCollapse, conn.cluster.minimumArea, conn.cluster.maximumArea); if (EditorGUI.EndChangeCheck() == true) RFCollapse.AreaCollapse (conn, conn.cluster.areaCollapse); EditorGUILayout.EndHorizontal(); GUICommon.Space (); GUILayout.BeginHorizontal(); GUILayout.Label (TextClp.str_size, GUILayout.Width (55)); // Start check for slider change EditorGUI.BeginChangeCheck(); conn.cluster.sizeCollapse = EditorGUILayout.Slider(conn.cluster.sizeCollapse, conn.cluster.minimumSize, conn.cluster.maximumSize); if (EditorGUI.EndChangeCheck() == true) RFCollapse.SizeCollapse (conn, conn.cluster.sizeCollapse); EditorGUILayout.EndHorizontal(); GUICommon.Space (); GUILayout.BeginHorizontal(); GUILayout.Label (TextClp.str_rand, GUILayout.Width (55)); // Start check for slider change EditorGUI.BeginChangeCheck(); conn.cluster.randomCollapse = EditorGUILayout.IntSlider(conn.cluster.randomCollapse, 0, 100); if (EditorGUI.EndChangeCheck() == true) RFCollapse.RandomCollapse (conn, conn.cluster.randomCollapse); EditorGUILayout.EndHorizontal(); } /// ///////////////////////////////////////////////////////// /// Stress /// ///////////////////////////////////////////////////////// void GUI_Stress() { GUICommon.CaptionBox (TextCnt.gui_cap_stress); GUICommon.PropertyField (sp_enable, TextStr.gui_enable); if (conn.stress.enable == true) { GUICommon.PropertyField (sp_showStress, TextCnt.gui_showStress); GUICommon.PropertyField (sp_startStress, TextCnt.gui_startStress); if (conn.startStress == RayfireConnectivity.RFConnInitType.ByIntegrity) GUICommon.IntSlider (sp_str_integrity, integrity_min, integrity_max, TextCnt.gui_integrity); GUICommon.Foldout (ref fld_props_str, TextKeys.con_fld_str, TextCnt.gui_fld_props.text); if (fld_props_str == true) GUI_Stress_Properties(); GUI_Stress_Buttons(); } } void GUI_Stress_Properties() { EditorGUI.indentLevel++; GUICommon.Caption (TextStr.gui_cap_conn); GUICommon.IntSlider (sp_threshold, threshold_min, threshold_max, TextStr.gui_threshold); GUICommon.Slider (sp_erosion, erosion_min, erosion_max, TextStr.gui_erosion); GUICommon.Slider (sp_interval, interval_min, interval_max, TextStr.gui_interval); GUICommon.Caption (TextStr.gui_cap_shards); GUICommon.IntSlider (sp_support, support_min, support_max, TextStr.gui_support); GUICommon.PropertyField (sp_exposed, TextStr.gui_exposed); GUICommon.PropertyField (sp_bySize, TextStr.gui_bySize); EditorGUI.indentLevel--; } void GUI_Stress_Buttons() { if (Application.isPlaying == true) { GUICommon.Space(); // Show start stress if not Start by default if (conn.stress.inProgress == false) { if (GUILayout.Button (TextCnt.gui_btn_str_start, GUILayout.Height (25))) foreach (var targ in targets) if (targ as RayfireConnectivity != null) RFStress.StartStress (targ as RayfireConnectivity); } // Show stop collapse if not Start by default if (conn.stress.inProgress == true) { if (GUILayout.Button (TextCnt.gui_btn_str_stop, GUILayout.Height (25))) foreach (var targ in targets) if (targ as RayfireConnectivity != null) RFStress.StopStress (targ as RayfireConnectivity); } } } /// ///////////////////////////////////////////////////////// /// Trigger /// ///////////////////////////////////////////////////////// // TODO update void GUI_Trigger() { GUICommon.CaptionBox (TextCnt.gui_cap_fracture); GUICommon.PropertyField (sp_triggerCollider, TextCnt.gui_triggerCollider); if (conn.clusterize == true) GUICommon.IntSlider (sp_triggerDebris, debris_min, debris_max, TextCnt.gui_triggerDebris); if (Application.isPlaying == true && conn.triggerCollider != null) { GUICommon.Space (); if (GUILayout.Button (TextCnt.gui_btn_fracture, GUILayout.Height (25))) if (Application.isPlaying == true) conn.Fracture (conn.triggerCollider, conn.triggerDebris); } } /// ///////////////////////////////////////////////////////// /// Joints /// ///////////////////////////////////////////////////////// void UI_Joints() { GUICommon.CaptionBox (TextCnt.gui_cap_joint); EditorGUI.BeginChangeCheck(); bool enable = EditorGUILayout.Toggle ("Enable", conn.joints.enable); if (EditorGUI.EndChangeCheck()) { Undo.RecordObjects (targets, "Enable"); foreach (RayfireConnectivity scr in targets) { scr.joints.enable = enable; SetDirty (scr); } } if (conn.joints.enable == true) { GUICommon.Space (); //exp_joints = EditorGUILayout.Foldout (exp_joints, "Properties", true); //if (exp_joints == true) { EditorGUI.indentLevel++; GUILayout.Label (" Break", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); conn.joints.breakType = (RFJointProperties.RFJointBreakType)EditorGUILayout.EnumPopup ("Type", conn.joints.breakType); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.breakType = conn.joints.breakType; SetDirty (scr); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.breakForce = EditorGUILayout.IntSlider ("Force", conn.joints.breakForce, 0, 5000); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.breakForce = conn.joints.breakForce; SetDirty (scr); if (Application.isPlaying == true) RFJointProperties.SetBreakForce (scr.joints.breakForce, scr.joints.breakForceVar, scr.joints.jointList, scr.joints.forceByMass); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.breakForceVar = EditorGUILayout.IntSlider ("Variation", conn.joints.breakForceVar, 0, 100); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.breakForceVar = conn.joints.breakForceVar; SetDirty (scr); if (Application.isPlaying == true) RFJointProperties.SetBreakForce (scr.joints.breakForce, scr.joints.breakForceVar, scr.joints.jointList, scr.joints.forceByMass); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.forceByMass = EditorGUILayout.Toggle ("Force By Mass", conn.joints.forceByMass); if (EditorGUI.EndChangeCheck()) foreach (RayfireConnectivity scr in targets) { scr.joints.forceByMass = conn.joints.forceByMass; SetDirty (scr); } GUICommon.Space (); GUILayout.Label (" Angular", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); conn.joints.angleLimit = EditorGUILayout.IntSlider ("Limit", conn.joints.angleLimit, 0, 50); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.angleLimit = conn.joints.angleLimit; SetDirty (scr); if (Application.isPlaying == true) RFJointProperties.SetAngularMotion (scr.joints.angleLimit, scr.joints.angleLimitVar, scr.joints.jointList); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.angleLimitVar = EditorGUILayout.IntSlider ("Variation", conn.joints.angleLimitVar, 0, 100); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.angleLimitVar = conn.joints.angleLimitVar; SetDirty (scr); if (Application.isPlaying == true) RFJointProperties.SetAngularMotion (scr.joints.angleLimit, scr.joints.angleLimitVar, scr.joints.jointList); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.damper = EditorGUILayout.IntSlider ("Damper", conn.joints.damper, 0, 10000); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.damper = conn.joints.damper; SetDirty (scr); if (Application.isPlaying == true) RFJointProperties.SetSpring (scr.joints.damper, scr.joints.jointList); } GUICommon.Space (); GUILayout.Label (" Deformation", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); conn.joints.deformEnable = EditorGUILayout.Toggle ("Enable", conn.joints.deformEnable); if (EditorGUI.EndChangeCheck()) foreach (RayfireConnectivity scr in targets) { scr.joints.deformEnable = conn.joints.deformEnable; SetDirty (scr); } if (conn.joints.deformEnable == true) { GUICommon.Space (); // Stiffness if (conn.joints.breakType == RFJointProperties.RFJointBreakType.Breakable) { EditorGUI.BeginChangeCheck(); conn.joints.stiffFrc = EditorGUILayout.Slider ("Stiffness", conn.joints.stiffFrc, 0.05f, 0.95f); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.stiffFrc = conn.joints.stiffFrc; SetDirty (scr); } } else { EditorGUI.BeginChangeCheck(); conn.joints.stiffAbs = EditorGUILayout.IntSlider ("Stiffness", conn.joints.stiffAbs, 1, 500); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.stiffAbs = conn.joints.stiffAbs; SetDirty (scr); } } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.bend = EditorGUILayout.IntSlider ("Bending", conn.joints.bend, 0, 10); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.bend = conn.joints.bend; SetDirty (scr); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.weakening = EditorGUILayout.Slider ("Weakening", conn.joints.weakening, 0, 0.9f); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.weakening = conn.joints.weakening; SetDirty (scr); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.percentage = EditorGUILayout.IntSlider ("Percentage", conn.joints.percentage, 1, 100); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.percentage = conn.joints.percentage; SetDirty (scr); } GUICommon.Space (); EditorGUI.BeginChangeCheck(); conn.joints.deformCount = EditorGUILayout.IntSlider ("Iterations", conn.joints.deformCount, 1, 100); if (EditorGUI.EndChangeCheck() == true) foreach (RayfireConnectivity scr in targets) { scr.joints.deformCount = conn.joints.deformCount; SetDirty (scr); } if (conn.joints.HasDeforms == true) { GUICommon.Space (); GUILayout.Label ("Deformable joints: " + conn.joints.deformList.Count + "/" + conn.joints.jointList.Count); } } // GUILayout.Label ("CurrentForce"); EditorGUI.indentLevel--; } } } /// ///////////////////////////////////////////////////////// /// Draw /// ///////////////////////////////////////////////////////// // Draw Connections and Nodes by act and uny states static void ClusterDraw(RFCluster cluster, bool showNodes, bool showConnections) { if (showNodes == true || showConnections == true) { if (cluster != null && cluster.shards.Count > 0) { for (int i = 0; i < cluster.shards.Count; i++) { if (cluster.shards[i].tm != null) { // Color if (cluster.shards[i].rigid == null) SetColor (cluster.shards[i].uny, cluster.shards[i].act); else { if (cluster.shards[i].rigid.objTp == ObjectType.Mesh) SetColor (cluster.shards[i].rigid.activation.uny, cluster.shards[i].rigid.activation.atb); else if (cluster.shards[i].rigid.objTp == ObjectType.MeshRoot || cluster.shards[i].rigid.objTp == ObjectType.ConnectedCluster) SetColor (cluster.shards[i].uny, cluster.shards[i].act); } // Nodes if (showNodes == true) Gizmos.DrawWireSphere (cluster.shards[i].tm.position, cluster.shards[i].sz / 12f); // Connection if (showConnections == true) { //Debug.Log (cluster.shards[i].nIds.Count); // Has no neibs if (cluster.shards[i].nIds.Count == 0) continue; // Shard has neibs but neib shards not initialized by nIds if (cluster.shards[i].neibShards == null) cluster.shards[i].neibShards = new List(); // Reinit if (cluster.shards[i].neibShards.Count == 0) for (int n = 0; n < cluster.shards[i].nIds.Count; n++) cluster.shards[i].neibShards.Add (cluster.shards[cluster.shards[i].nIds[n]]); // Preview for (int j = 0; j < cluster.shards[i].neibShards.Count; j++) if (cluster.shards[i].neibShards[j].tm != null) { Gizmos.DrawLine (cluster.shards[i].tm.position, (cluster.shards[i].neibShards[j].tm.position - cluster.shards[i].tm.position) / 2f + cluster.shards[i].tm.position); } } } } } } } // Draw stressed connections static void StressDraw (RayfireConnectivity targ) { if (targ.showStress == true && targ.stress != null && targ.stress.inProgress == true) { if (targ.cluster != null && targ.cluster.shards.Count > 0) { Vector3 pos; for (int i = 0; i < targ.cluster.shards.Count; i++) { if (targ.cluster.shards[i].tm != null) { // Show Path stress /* if (false) if (targ.stress.bySize == true) { Gizmos.color = ColorByValue (stressColor, targ.cluster.shards[i].sSt, 1f); Gizmos.DrawWireSphere (targ.cluster.shards[i].tm.position, targ.cluster.shards[i].sz / 12f); } */ if (targ.cluster.shards[i].StressState == true) { for (int n = 0; n < targ.cluster.shards[i].nSt.Count / 3; n++) { if (targ.cluster.shards[i].uny == true) { Gizmos.color = Color.yellow; } else { Gizmos.color = targ.cluster.shards[i].sIds.Count > 0 ? Color.yellow : ColorByValue (stressColor, targ.cluster.shards[i].nSt[n * 3], targ.stress.threshold); } pos = (targ.cluster.shards[i].neibShards[n].tm.position - targ.cluster.shards[i].tm.position) / 2.5f + targ.cluster.shards[i].tm.position; Gizmos.DrawLine (targ.cluster.shards[i].tm.position, pos); } } } } } } } // Set gizmo color by uny and act states static void SetColor (bool uny, bool act) { if (uny == false) Gizmos.color = Color.green; else Gizmos.color = act == true ? Color.magenta : Color.red; } // Color by value static Color ColorByValue(Color color, float val, float threshold) { val /= threshold; color.g = 1f - val; color.r = val; return color; } /// ///////////////////////////////////////////////////////// /// Methods /// ///////////////////////////////////////////////////////// [DrawGizmo (GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)] static void DrawGizmosSelected (RayfireConnectivity targ, GizmoType gizmoType) { // Draw bounding gizmo GizmoDraw (targ); // Has no shards if (targ.cluster == null) return; /* // Missing shards // if (targ.cluster.shards.Count > 0) { if (RFCluster.IntegrityCheck (targ.cluster) == false) Debug.Log ("RayFire Connectivity: " + targ.name + " has missing shards. Reset or Setup cluster.", targ.gameObject); else targ.integrityCheck = false; } */ // Draw for MeshRoot and RigidRoot in runtime if (Application.isPlaying == true || targ.meshRootHost != null) { ClusterDraw (targ.cluster, targ.showNodes, targ.showConnections); } // Draw for RigidRoot because Connectivity do not store same shard list else if (targ.rigidRootHost != null) ClusterDraw (targ.rigidRootHost.cluster, targ.showNodes, targ.showConnections); // Draw stresses connections StressDraw (targ); } static void GizmoDraw (RayfireConnectivity targ) { if (targ.showGizmo == true) { // Gizmo properties Gizmos.color = GUICommon.color_blue; if (targ.transform.childCount > 0) { Bounds bound = RFCluster.GetChildrenBound (targ.transform); Gizmos.DrawWireCube (bound.center, bound.size); } } } /// ///////////////////////////////////////////////////////// /// Common /// ///////////////////////////////////////////////////////// void SetDirty (RayfireConnectivity scr) { if (Application.isPlaying == false) { EditorUtility.SetDirty (scr); EditorSceneManager.MarkSceneDirty (scr.gameObject.scene); SceneView.RepaintAll(); } } } } /* /// ///////////////////////////////////////////////////////// /// Handle selection /// ///////////////////////////////////////////////////////// static Vector2Int currentShardConnection; private static int s_ButtonHash = "ConnectionHandle".GetHashCode(); void OnSceneGUI() { var targ = conn; if (targ == null) return; if (targ.showConnections == true) { if (targ.cluster != null && targ.cluster.shards.Count > 0) { int count = targ.cluster.shards.Count; for (int i = 0; i < count; i++) { if (targ.cluster.shards[i].tm != null) { if (targ.cluster.shards[i].nIds.Count == 0) continue; if (targ.cluster.shards[i].neibShards != null && targ.cluster.shards[i].neibShards.Count != 0) { int nCount = targ.cluster.shards[i].neibShards.Count; for (int j = 0; j < nCount; j++) { if (targ.cluster.shards[i].neibShards[j].tm != null) { Vector3 start = targ.cluster.shards[i].tm.position; Vector3 end = start + (targ.cluster.shards[i].neibShards[j].tm.position - start) * 0.5f; HandleClick(start, end, targ.cluster.shards[i].id, targ.cluster.shards[i].neibShards[j].id); } } } } } } } } private static void HandleClick(Vector3 start, Vector3 end, int id1, int id2) { int id = GUIUtility.GetControlID(s_ButtonHash, FocusType.Passive); Event evt = Event.current; switch (evt.GetTypeForControl(id)) { case EventType.Layout: { HandleUtility.AddControl(id, HandleUtility.DistanceToLine(start, end)); break; } case EventType.MouseMove: { if (id == HandleUtility.nearestControl) HandleUtility.Repaint(); break; } case EventType.MouseDown: { if (HandleUtility.nearestControl == id && evt.button == 0) { GUIUtility.hotControl = id; // Grab mouse focus HandleClickSelection(evt, id1, id2); evt.Use(); } break; } } } public static void HandleClickSelection(Event evt, int id1, int id2) { currentShardConnection.x = id1; currentShardConnection.y = id2; } private void DeleteSelectedConnection() { var targ = conn; if (targ.showConnections == true) { if (targ.cluster != null && targ.cluster.shards.Count > 0) { int count = targ.cluster.shards.Count; for (int i = 0; i < count; i++) { if (targ.cluster.shards[i].tm != null) { if (targ.cluster.shards[i].nIds.Count == 0) continue; if (targ.cluster.shards[i].neibShards != null && targ.cluster.shards[i].neibShards.Count != 0) { int nCount = targ.cluster.shards[i].neibShards.Count - 1; for (int j = nCount; j >= 0; --j) { if (targ.cluster.shards[i].neibShards[j].tm != null) { var id = targ.cluster.shards[i].id; var nId = targ.cluster.shards[i].neibShards[j].id; if (currentShardConnection.x == id && currentShardConnection.y == nId || currentShardConnection.y == id && currentShardConnection.x == nId) targ.cluster.shards[i].RemoveNeibAt(j); } } } } } } } } */ /* if (targ.cluster.shards[i].uny == true) { Gizmos.color = Color.yellow; } else { //if (targ.cluster.shards[i].sIds.Count > 0) //{ if (targ.cluster.shards[i].neibShards[n].sIds.Contains (targ.cluster.shards[i].id) == true || targ.cluster.shards[i].sIds.Contains (targ.cluster.shards[i].neibShards[n].id) == true) { Gizmos.color = Color.yellow; } //} else Gizmos.color = ColorByValue (stressColor, targ.cluster.shards[i].nStr[n * 3], targ.stress.threshold); } if (targ.cluster.shards[i].uny == true || targ.cluster.shards[i].sIds.Count > 0) Gizmos.color = Color.yellow; else Gizmos.color = ColorByValue (stressColor, targ.cluster.shards[i].nStr[n*3], targ.stress.threshold); */