Renamed IVideo implementations
To match the interface they are implementing.
This commit is contained in:
committed by
Matthias Mailänder
parent
6f0509d235
commit
248b8d1102
156
OpenRA.Mods.Cnc/FileFormats/WsaVideo.cs
Normal file
156
OpenRA.Mods.Cnc/FileFormats/WsaVideo.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2021 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using OpenRA.Video;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.FileFormats
|
||||
{
|
||||
public class WsaVideo : IVideo
|
||||
{
|
||||
public ushort FrameCount { get; }
|
||||
public byte Framerate => 1;
|
||||
public ushort Width { get; }
|
||||
public ushort Height { get; }
|
||||
|
||||
public byte[] CurrentFrameData { get; }
|
||||
public int CurrentFrameNumber { get; private set; }
|
||||
|
||||
public bool HasAudio => false;
|
||||
public byte[] AudioData => null;
|
||||
public int AudioChannels => 0;
|
||||
public int SampleBits => 0;
|
||||
public int SampleRate => 0;
|
||||
|
||||
readonly Stream stream;
|
||||
readonly byte[] paletteBytes;
|
||||
readonly uint[] frameOffsets;
|
||||
readonly ushort totalFrameWidth;
|
||||
|
||||
byte[] previousFramePaletteIndexData;
|
||||
byte[] currentFramePaletteIndexData;
|
||||
|
||||
public WsaVideo(Stream stream, bool useFramePadding)
|
||||
{
|
||||
this.stream = stream;
|
||||
|
||||
FrameCount = stream.ReadUInt16();
|
||||
|
||||
/*var x = */stream.ReadUInt16();
|
||||
/*var y = */stream.ReadUInt16();
|
||||
|
||||
Width = stream.ReadUInt16();
|
||||
Height = stream.ReadUInt16();
|
||||
|
||||
var delta = stream.ReadUInt16() + 37;
|
||||
var flags = stream.ReadUInt16();
|
||||
|
||||
frameOffsets = new uint[FrameCount + 2];
|
||||
for (var i = 0; i < frameOffsets.Length; i++)
|
||||
frameOffsets[i] = stream.ReadUInt32();
|
||||
|
||||
if (flags == 1)
|
||||
{
|
||||
paletteBytes = new byte[1024];
|
||||
for (var i = 0; i < paletteBytes.Length;)
|
||||
{
|
||||
var r = (byte)(stream.ReadByte() << 2);
|
||||
var g = (byte)(stream.ReadByte() << 2);
|
||||
var b = (byte)(stream.ReadByte() << 2);
|
||||
|
||||
// Replicate high bits into the (currently zero) low bits.
|
||||
r |= (byte)(r >> 6);
|
||||
g |= (byte)(g >> 6);
|
||||
b |= (byte)(b >> 6);
|
||||
|
||||
paletteBytes[i++] = b;
|
||||
paletteBytes[i++] = g;
|
||||
paletteBytes[i++] = r;
|
||||
paletteBytes[i++] = 255;
|
||||
}
|
||||
|
||||
for (var i = 0; i < frameOffsets.Length; i++)
|
||||
frameOffsets[i] += 768;
|
||||
}
|
||||
|
||||
if (useFramePadding)
|
||||
{
|
||||
var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height));
|
||||
CurrentFrameData = new byte[frameSize * frameSize * 4];
|
||||
totalFrameWidth = (ushort)frameSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentFrameData = new byte[Width * Height * 4];
|
||||
totalFrameWidth = Width;
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
CurrentFrameNumber = 0;
|
||||
previousFramePaletteIndexData = null;
|
||||
LoadFrame();
|
||||
}
|
||||
|
||||
public void AdvanceFrame()
|
||||
{
|
||||
previousFramePaletteIndexData = currentFramePaletteIndexData;
|
||||
CurrentFrameNumber++;
|
||||
LoadFrame();
|
||||
}
|
||||
|
||||
void LoadFrame()
|
||||
{
|
||||
if (CurrentFrameNumber >= FrameCount)
|
||||
return;
|
||||
|
||||
stream.Seek(frameOffsets[CurrentFrameNumber], SeekOrigin.Begin);
|
||||
|
||||
var dataLength = frameOffsets[CurrentFrameNumber + 1] - frameOffsets[CurrentFrameNumber];
|
||||
|
||||
var rawData = StreamExts.ReadBytes(stream, (int)dataLength);
|
||||
var intermediateData = new byte[Width * Height];
|
||||
|
||||
// Format80 decompression
|
||||
LCWCompression.DecodeInto(rawData, intermediateData);
|
||||
|
||||
// and Format40 decompression
|
||||
currentFramePaletteIndexData = new byte[Width * Height];
|
||||
if (previousFramePaletteIndexData == null)
|
||||
Array.Clear(currentFramePaletteIndexData, 0, currentFramePaletteIndexData.Length);
|
||||
else
|
||||
Array.Copy(previousFramePaletteIndexData, currentFramePaletteIndexData, currentFramePaletteIndexData.Length);
|
||||
|
||||
XORDeltaCompression.DecodeInto(intermediateData, currentFramePaletteIndexData, 0);
|
||||
|
||||
var c = 0;
|
||||
var position = 0;
|
||||
for (var y = 0; y < Height; y++)
|
||||
{
|
||||
for (var x = 0; x < Width; x++)
|
||||
{
|
||||
var colorIndex = currentFramePaletteIndexData[c++];
|
||||
CurrentFrameData[position++] = paletteBytes[colorIndex * 4];
|
||||
CurrentFrameData[position++] = paletteBytes[colorIndex * 4 + 1];
|
||||
CurrentFrameData[position++] = paletteBytes[colorIndex * 4 + 2];
|
||||
CurrentFrameData[position++] = paletteBytes[colorIndex * 4 + 3];
|
||||
}
|
||||
|
||||
// Recalculate the position in the byte array to the start of the next pixel row just in case there is padding in the frame.
|
||||
position = (y + 1) * totalFrameWidth * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user