private static IEnumerable <AssLine> CreateFrameLines(AssDocument document, AssLine originalLine, TimeRange timeRange, List <AnimationWithSectionIndex> animations) { int rangeStartFrame = TimeUtil.StartTimeToFrame(timeRange.Start); int rangeEndFrame = TimeUtil.EndTimeToFrame(timeRange.End); const int frameStepSize = 2; int subStepFrames = (rangeEndFrame + 1 - rangeStartFrame) % frameStepSize; int lastIterationFrame = rangeEndFrame + 1 - subStepFrames - frameStepSize; bool needTextReset = animations.Any(a => a.Animation.AffectsText); AssLine frameLine = originalLine; for (int frame = rangeStartFrame; frame <= lastIterationFrame; frame += frameStepSize) { frameLine = (AssLine)frameLine.Clone(); frameLine.Start = TimeUtil.FrameToStartTime(frame); frameLine.End = frame < lastIterationFrame?TimeUtil.FrameToEndTime(frame + frameStepSize - 1) : timeRange.End; frameLine.Position = originalLine.Position ?? document.GetDefaultPosition(originalLine.AnchorPoint); if (needTextReset) { ResetText(frameLine, originalLine); } float interpFrame = frame + (frameStepSize - 1) / 2.0f; foreach (AnimationWithSectionIndex animWithSection in animations) { int animStartFrame = TimeUtil.StartTimeToFrame(animWithSection.Animation.StartTime); int animEndFrame = TimeUtil.EndTimeToFrame(animWithSection.Animation.EndTime); if (interpFrame >= animStartFrame && interpFrame < animEndFrame) { float t = (interpFrame - animStartFrame) / (animEndFrame - animStartFrame); ApplyAnimation(frameLine, animWithSection, t); } else if (interpFrame >= animEndFrame && interpFrame < animEndFrame + frameStepSize) { ApplyAnimation(frameLine, animWithSection, 1); } } yield return(frameLine); } }