/// <summary> /// 更新物件,因为是增量更新维护,所以current_time递减或变小时,必须先Flush()后Update(). /// </summary> /// <param name="current_time"></param> public void Update(float current_time) { if (current_time < prev_time) { Flush(); } else { UpdatingStoryboardObjects.RemoveAll((obj) => (current_time > obj.FrameEndTime || current_time < obj.FrameStartTime) && (obj.CurrentUpdater = null) == null /*clean CurrentUpdater*/); } prev_time = current_time; bool hasAdded = Scan(current_time); if (hasAdded) { UpdatingStoryboardObjects.Sort((a, b) => { return(a.Z - b.Z); }); } var need_parallel = UpdatingStoryboardObjects.Count >= Setting.ParallelUpdateObjectsLimitCount && Setting.ParallelUpdateObjectsLimitCount != 0; ParallelableForeachExecutor.Foreach(need_parallel, UpdatingStoryboardObjects, obj => obj.Update(current_time)); }
/* * MX,0,94938,130595,320 ---simplify---> MX,0,94938,94938,320,320 * * it could avoid a part cause about command conflict: * MX,0,94938,130595,320 * M,20,95008,95078,320,240,322.9271,226.3689 * M,20,95078,95148,322.9271,226.3689,320.6659,236.2696 * M,20,95148,95218,320.6659,236.2696,321.3301,232.5321 */ private void TrimHoldingStatusCommand(IEnumerable <StoryboardObject> storyboard_objects, ref int effect_count) { var x = 0; ParallelableForeachExecutor.Foreach(true, storyboard_objects, obj => { foreach (CommandTimeline timeline in obj.CommandMap.Values) { if (!timeline.Overlay) { continue; } for (int i = 0; i < timeline.Count; i++) { if (timeline[i] is ValueCommand cmd) { if (cmd.EqualityComparer.Equals(cmd.GetEndValue(), cmd.GetStartValue()) && cmd.Easing == EasingTypes.None) { timeline.Remove(cmd); cmd.EndTime = cmd.StartTime; timeline.Add(cmd); x++; } } } } }); effect_count = x; }
/// <summary> /// 计算Fade时间轴,优化物件的FrameStartTime/EndTime,避免不必要的计算 /// 点名批评 -> 181957 /// /// ///Sprite,Foreground,Centre,"sb\light.png",320,240 /// S,0,0,,0.22 <----Non-optimze obj.FrameStartTime /// MX,0,0,,278 /// F,0,126739,,0 <----Kill by Optimzer /// F,0,208016,,0.7,1 <----Actual obj.FrameStartTime /// C,0,208016,,255,255,255 /// P,0,208016,,A /// MY,0,208016,209286,520,-40 <----Actual obj.FrameEndTime /// /// </summary> /// <param name="Storyboard_objects"></param> /// <param name="effect_count"></param> public void TrimFrameTime(IEnumerable <StoryboardObject> Storyboard_objects, ref int effect_count) { var t = 0; ParallelableForeachExecutor.Foreach(true, Storyboard_objects, obj => { if (obj == null || obj is StoryboardAnimation || //qnmd !obj.CommandMap.TryGetValue(Event.Fade, out var fade_list) || fade_list.Count == 0 || fade_list.Overlay || fade_list.Count <= 1 ) { return; } var first_fade = fade_list.First() as FadeCommand; if (first_fade != null) { FadeCommand front_fade = null; if ((first_fade.EndTime == 0 || first_fade.StartTime == first_fade.EndTime) && //是否为立即命令(dutation=0) first_fade.EndValue == 0) //是否是隐藏的 { if (fade_list.Skip(1).First() is FadeCommand second_fade) { front_fade = second_fade; } } else if (first_fade.StartValue == 0) { front_fade = first_fade; } if (front_fade != null && obj.FrameStartTime <= front_fade.StartTime) { var trigger_time = obj.ContainTrigger ? obj.CommandMap[Event.Trigger].Min(x => x.StartTime) : int.MaxValue; var trim_start_time = Math.Min(trigger_time, front_fade.StartTime); obj.BaseTransformResetAction += x => x.FrameStartTime = trim_start_time; obj.FrameStartTime = trim_start_time; Suggest(obj, $"FrameTime可优化成{front_fade.StartTime}"); t++; } } var last_fade = fade_list.Last() as FadeCommand; if (last_fade != null && last_fade.EndValue == 0) { obj.FrameEndTime = last_fade.EndTime; Suggest(obj, $"EndTime可优化成{last_fade.StartTime}."); t++; } }); effect_count = t; }
public void CombineCommands(IEnumerable <StoryboardObject> Storyboard_objects, ref int effect_count) { var t = 0; ParallelableForeachExecutor.Foreach(true, Storyboard_objects, obj => { foreach (var pair in obj.CommandMap) { var real_timeline = pair.Value; //立即求值 var normal_timeline = pair.Value.OfType <ValueCommand>().ToArray(); if (normal_timeline.Length == 0) { continue; } //ValueCommand<TYPE_VALUE>我敲里吗 var type = normal_timeline.First().GetType(); var end_value_prop = type.GetField("EndValue"); var start_value_prop = type.GetField("StartValue"); for (int i = 0; i < normal_timeline.Count() - 1; i++) { var cmd = normal_timeline[i]; var next_cmd = normal_timeline[i + 1]; if ((cmd.Easing == next_cmd.Easing) && (cmd.EndTime == next_cmd.StartTime) && (end_value_prop.GetValue(cmd) == start_value_prop.GetValue(next_cmd))) { //combine var new_cmd = (ValueCommand)type.Assembly.CreateInstance(type.FullName); new_cmd.EndTime = next_cmd.EndTime; new_cmd.StartTime = cmd.StartTime; new_cmd.Easing = cmd.Easing; end_value_prop.SetValue(new_cmd, end_value_prop.GetValue(next_cmd)); start_value_prop.SetValue(new_cmd, start_value_prop.GetValue(cmd)); //remove old var index = real_timeline.IndexOf(cmd); real_timeline.Remove(cmd); real_timeline.Remove(next_cmd); //insert new real_timeline.Add(new_cmd); //skip next command i++; t++; } } } }); effect_count = t; }
/// <summary> /// 将时间轴单个立即命令直接应用到物件上,减少物件执行命令频率 /// 点名批评 -> 181957 /// ///Sprite,Foreground,Centre,"sb\light.png",320,240 /// S,0,0,,0.22 <---- Set as Object.Scale inital value by Optimzer /// MX,0,0,,278 <---- Set as Object.Position.X inital value by Optimzer /// F,0,126739,,0 /// F,0,208016,,0.7,1 /// C,0,208016,,255,255,255 /// P,0,208016,,A <---- Set as Object.IsAdditive value by Optimzer /// MY,0,208016,209286,520,-40 /// /// </summary> /// <param name="Storyboard_objects"></param> /// <param name="effect_count"></param> public void TrimInitalEffect(IEnumerable <StoryboardObject> Storyboard_objects, ref int effect_count) { var events = Enum.GetValues(typeof(Event)); var t = 0; ParallelableForeachExecutor.Foreach(true, Storyboard_objects, obj => { //物件命令数量!=0 且 无Trigger对应类型的子命令 foreach (var timeline in obj.CommandMap.Where(x => x.Value.Count == 1 && ((!obj.ContainTrigger) || ( !obj.CommandMap[Event.Trigger] .OfType <GroupCommand>() .SelectMany( l => l.SubCommands .Where(w => w.Key == x.Key)).Select(m => m.Value) .Any()))).Select(e => e.Value)) { Command cmd = timeline.FirstOrDefault(); if (cmd.EndTime <= obj.FrameStartTime && cmd.StartTime == cmd.EndTime //C,0,0,,0,0,0,226,172,247 && ((cmd is ValueCommand) /*&&(vcmd.EqualityComparer.Equals(vcmd.GetEndValue(), vcmd.GetStartValue()))*/ || cmd is StateCommand)) { /* * 低于时间或者初始变化值 都相同 的命令可以直接应用到物件上 */ timeline.Remove(cmd); obj.BaseTransformResetAction += (target) => { cmd.Execute(target, cmd.EndTime + 1); }; t++; } } //去掉没有命令的时间轴 foreach (Event e in events) { if (obj.CommandMap.TryGetValue(e, out var timeline) && timeline.Count == 0) { obj.CommandMap.Remove(e); t++; } } }); effect_count = t; }
/// <summary> /// 删除无用的命令,即理论上根本不会被执行到的命令 /// 点名批评 -> 381480 /// /// /// </summary> /// <param name="Storyboard_objects"></param> /// <param name="effect_count"></param> public void RemoveUnusedCommand(IEnumerable <StoryboardObject> Storyboard_objects, ref int effect_count) { Event[] skip_event = new[] { Event.Loop, Event.Trigger }; var z = 0; ParallelableForeachExecutor.Foreach(true, Storyboard_objects, obj => { foreach (var timeline in obj.CommandMap.Where(x => !skip_event.Contains(x.Key)).Select(x => x.Value)) { for (int i = 0; timeline.Overlay && i < timeline.Count - 1; i++) { var cmd = timeline[i]; /* *(cmd) : |--------------------------| *(next_cmd) : |--------------| <--- Killed , biatch */ for (int t = i + 1; timeline.Overlay && t < timeline.Count; t++) { var next_cmd = timeline[t]; if (next_cmd.StartTime > cmd.EndTime) { break; } if ( next_cmd.EndTime <= cmd.EndTime && next_cmd.EndTime != next_cmd.StartTime && cmd.CompareTo(next_cmd) <= 0) { timeline.Remove(next_cmd); Log.Debug($"Remove unused command ({next_cmd}) in ({obj}),compare with ({cmd})"); Suggest(next_cmd, $"此命令被\"{cmd}\"命令覆盖而不被执行到,可删除"); z++; } } } } }); effect_count = z; }