diff --git a/OpenRA.FileFormats/Graphics/VqaReader.cs b/OpenRA.FileFormats/Graphics/VqaReader.cs index 84658e94b8..d6cb32198e 100644 --- a/OpenRA.FileFormats/Graphics/VqaReader.cs +++ b/OpenRA.FileFormats/Graphics/VqaReader.cs @@ -109,11 +109,15 @@ namespace OpenRA.FileFormats CollectAudioData(); - // Load the first frame - currentFrame = 0; - AdvanceFrame(); + Reset(); } - + + public void Reset() + { + currentFrame = cbOffset = cbChunk = 0; + LoadFrame(); + } + void CollectAudioData() { var ms = new MemoryStream(); @@ -147,9 +151,18 @@ namespace OpenRA.FileFormats audioData = AudLoader.LoadSound(ms.ToArray(), ref adpcmIndex); } - + public void AdvanceFrame() + { + currentFrame++; + LoadFrame(); + } + + void LoadFrame() { + if (currentFrame >= Frames) + return; + // Seek to the start of the frame stream.Seek(offsets[currentFrame], SeekOrigin.Begin); BinaryReader reader = new BinaryReader(stream); @@ -176,8 +189,6 @@ namespace OpenRA.FileFormats // Chunks are aligned on even bytes; advance by a byte if the next one is null if (reader.PeekChar() == 0) reader.ReadByte(); } - if (++currentFrame == Frames) - currentFrame = cbOffset = cbChunk = 0; } // VQA Frame diff --git a/OpenRA.Game/Widgets/VqaPlayerWidget.cs b/OpenRA.Game/Widgets/VqaPlayerWidget.cs index 056111c184..ea79d8280f 100644 --- a/OpenRA.Game/Widgets/VqaPlayerWidget.cs +++ b/OpenRA.Game/Widgets/VqaPlayerWidget.cs @@ -12,6 +12,7 @@ using System; using System.Drawing; using OpenRA.FileFormats; using OpenRA.Graphics; +using OpenRA.Support; namespace OpenRA.Widgets { @@ -23,41 +24,42 @@ namespace OpenRA.Widgets Sprite videoSprite; VqaReader video = null; + float invLength; public void LoadVideo(string filename) { video = new VqaReader(FileSystem.Open(filename)); - timestep = 1e3f/video.Framerate; - + timestep = 1f/video.Framerate; + invLength = video.Framerate*1f/video.Frames; + var size = OpenRA.Graphics.Util.NextPowerOf2(Math.Max(video.Width, video.Height)); videoSprite = new Sprite(new Sheet(new Size(size,size)), new Rectangle( 0, 0, video.Width, video.Height ), TextureChannel.Alpha); } - int lastTime; + bool first = true; bool advanceNext = false; + Stopwatch sw = new Stopwatch(); public override void DrawInner(World world) { if (video == null) - { - LoadVideo(Video); - Sound.PlayRaw(video.AudioData); - } - - int t = Environment.TickCount; - int dt = t - lastTime; - - if (advanceNext) - { - if (video.CurrentFrame == 0) - Sound.PlayRaw(video.AudioData); - advanceNext = false; - video.AdvanceFrame(); - } - - if (dt > timestep) + LoadVideo(Video); + + var nextFrame = (int)float2.Lerp(0, video.Frames, (float)(sw.ElapsedTime()*invLength)); + if (first || nextFrame > video.Frames) { - lastTime = t; - advanceNext = true; + video.Reset(); + sw.Reset(); + Sound.PlayRaw(video.AudioData); + + nextFrame = 0; videoSprite.sheet.Texture.SetData(video.FrameData()); + first = false; + } + + while (nextFrame > video.CurrentFrame) + { + video.AdvanceFrame(); + if (nextFrame == video.CurrentFrame) + videoSprite.sheet.Texture.SetData(video.FrameData()); } Game.Renderer.RgbaSpriteRenderer.DrawSprite(videoSprite, new int2(RenderBounds.X,RenderBounds.Y), "chrome");