/// Leaves stream in indeterminate state; caller should Close() upon return. public static bool ReadMemory(Stream stream, Guid[] brushList, bool bAdditive, out bool isLegacy, out Dictionary <int, int> oldGroupToNewGroup) { bool allowFastPath = BitConverter.IsLittleEndian; // Buffering speeds up fast path ~1.4x, slow path ~2.3x var bufferedStream = new BufferedStream(stream, 4096); // var stopwatch = new System.Diagnostics.Stopwatch(); // stopwatch.Start(); isLegacy = false; SketchMemoryScript.m_Instance.ClearRedo(); if (!bAdditive) { //clean up old draw'ring SketchMemoryScript.m_Instance.ClearMemory(); } #if (UNITY_EDITOR || EXPERIMENTAL_ENABLED) if (Config.IsExperimental) { if (App.Config.m_ReplaceBrushesOnLoad) { brushList = brushList.Select(guid => App.Config.GetReplacementBrush(guid)).ToArray(); } } #endif oldGroupToNewGroup = new Dictionary <int, int>(); var strokes = GetStrokes(bufferedStream, brushList, allowFastPath); if (strokes == null) { return(false); } // Check that the strokes are in timestamp order. uint headMs = uint.MinValue; foreach (var stroke in strokes) { if (stroke.HeadTimestampMs < headMs) { strokes.Sort((a, b) => a.HeadTimestampMs.CompareTo(b.HeadTimestampMs)); ControllerConsoleScript.m_Instance.AddNewLine("Bad timing data detected. Please re-save."); Debug.LogAssertion("Unsorted timing data in sketch detected. Strokes re-sorted."); break; } headMs = stroke.HeadTimestampMs; } QualityControls.m_Instance.AutoAdjustSimplifierLevel(strokes, brushList); foreach (var stroke in strokes) { // Deserialized strokes are expected in timestamp order, yielding aggregate complexity // of O(N) to populate the by-time linked list. SketchMemoryScript.m_Instance.MemoryListAdd(stroke); } // stopwatch.Stop(); // Debug.LogFormat("Reading took {0}", stopwatch.Elapsed); GroupManager.MoveStrokesToNewGroups(strokes, oldGroupToNewGroup); return(true); }