using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; namespace RayFire { [Serializable] public class RFRuntimeCaching { [FormerlySerializedAs ("type")] public CachingType tp; [FormerlySerializedAs ("frames")] public int frm; [FormerlySerializedAs ("fragments")] public int frg; [FormerlySerializedAs ("skipFirstDemolition")] public bool skp; [NonSerialized] public bool inProgress; [NonSerialized] public bool wasUsed; [NonSerialized] public bool stop; /// ///////////////////////////////////////////////////////// /// Constructor /// ///////////////////////////////////////////////////////// // Constructor public RFRuntimeCaching() { InitValues(); } // Starting values public void InitValues() { tp = CachingType.Disabled; frm = 3; frg = 4; skp = false; } // Copy from public void CopyFrom (RFRuntimeCaching rc) { tp = rc.tp; frm = rc.frm; frg = rc.frg; skp = rc.skp; } /// ///////////////////////////////////////////////////////// /// Static /// ///////////////////////////////////////////////////////// // Get batches amount for continuous fragmentation public static List GetBatchByFrames (int frames, int amount) { // Get basic list int div = amount / frames; List batchAmount = new List(frames + 1); for (int i = 0; i < frames; i++) batchAmount.Add (div); // Consider difference int dif = amount % frames; if (dif > 0) for (int i = 0; i < dif; i++) batchAmount[i] += 1; // Remove 0 if (frames > amount) for (int i = batchAmount.Count - 1; i >= 0; i--) if (batchAmount[i] == 0) batchAmount.RemoveAt (i); return batchAmount; } // Get batches amount for continuous fragmentation public static List GetBatchByFragments (int fragments, int amount) { // Get basic list int steps = amount / fragments; List batchAmount = new List(steps + 1); if (steps > 0) for (int i = 0; i < steps; i++) batchAmount.Add (fragments); // Consider difference int dif = amount % fragments; if (dif > 0) batchAmount.Add (dif); return batchAmount; } // Get list of marked elements index public static List GetMarkedElements (int batchInd, List batchAmount) { // Get offset int offset = 0; if (batchInd > 0) for (int i = 0; i < batchInd; i++) offset += batchAmount[i]; // Collect marked elements ids List markedElements = new List(batchAmount[batchInd]); for (int i = 0; i < batchAmount[batchInd]; i++) markedElements.Add (i + offset); return markedElements; } // Create tm reference public static GameObject CreateTmRef(RayfireRigid rfScr) { GameObject go = new GameObject("RFTempGo"); go.SetActive (false); go.transform.position = rfScr.tsf.position; go.transform.rotation = rfScr.tsf.rotation; go.transform.localScale = rfScr.tsf.localScale; go.transform.parent = RayfireMan.inst.transform; return go; } /// ///////////////////////////////////////////////////////// /// Methods /// ///////////////////////////////////////////////////////// // Cor to fragment mesh over several frames public IEnumerator RuntimeCachingCor (RayfireRigid scr) { // Object should be demolished when cached all meshes but not during caching bool demolitionShouldLocal = scr.limitations.demolitionShould == true; scr.limitations.demolitionShould = false; // Input mesh, setup, record time float t1 = Time.realtimeSinceStartup; if (RFFragment.InputMesh (scr) == false) yield break; // Set list with amount of mesh for every frame List batchAmount = tp == CachingType.ByFrames ? GetBatchByFrames(frm, scr.mshDemol.totalAmount) : GetBatchByFragments(frg, scr.mshDemol.totalAmount); // Caching in progress inProgress = true; // Wait next frame if input took too much time or long batch float t2 = Time.realtimeSinceStartup - t1; if (t2 > 0.02f || batchAmount.Count > 5) yield return null; // Save tm for multi frame caching GameObject tmRefGo = CreateTmRef (scr); // Start rotation scr.mshDemol.rotStart = scr.tsf.rotation; // Iterate every frame. Calc local frame meshes List meshesList = new List(); List pivotsList = new List(); List subList = new List(); for (int i = 0; i < batchAmount.Count; i++) { // Check for stop if (stop == true) { ResetRuntimeCaching(scr, tmRefGo); yield break; } // Cache defined points RFFragment.CacheMeshesMult (tmRefGo.transform, ref meshesList, ref pivotsList, ref subList, scr, batchAmount, i); // TODO create fragments for current batch // TODO record time and decrease batches amount if less 30 fps yield return null; } // Set to main data vars scr.meshes = meshesList.ToArray(); scr.pivots = pivotsList.ToArray(); scr.subIds = subList.ToArray();; // Clear scr.DestroyObject (tmRefGo); scr.mshDemol.sht = null; // Set demolition ready state if (skp == false && demolitionShouldLocal == true) { scr.limitations.demolitionShould = true; // Add to demolition cor RayfireMan.inst.AddToDemolitionCor(scr); } // Reset damage if (skp == true && demolitionShouldLocal == true) scr.damage.LocalReset(); // Caching finished inProgress = false; wasUsed = true; } // Stop runtime caching and reset it public void StopRuntimeCaching() { if (inProgress == true) stop = true; } // Reset caching void ResetRuntimeCaching (RayfireRigid scr, GameObject tmRefGo) { scr.DestroyObject (tmRefGo); stop = false; inProgress = false; scr.mshDemol.rfShatter = null; scr.DeleteCache(); } } }