Add AVFX parsing.

This commit is contained in:
Ottermandias 2022-12-31 01:18:58 +01:00
parent 3eb35c479e
commit 6cd43aa304
2 changed files with 419 additions and 0 deletions

View file

@ -0,0 +1,282 @@
using System;
using System.IO;
using System.Numerics;
using System.Text;
namespace Penumbra.GameData.Files;
public class AvfxFile : IWritable
{
public struct Block
{
public uint Name;
public uint Size;
public byte[] Data;
public Block(BinaryReader r)
{
Name = r.ReadUInt32();
Size = r.ReadUInt32();
Data = r.ReadBytes((int)Size.RoundTo4());
}
public bool ToBool()
=> BitConverter.ToBoolean(Data);
public uint ToUint()
=> BitConverter.ToUInt32(Data);
public float ToFloat()
=> BitConverter.ToSingle(Data);
public new string ToString()
{
var span = Data.AsSpan(0, (int)Size - 1);
return Encoding.UTF8.GetString(span);
}
}
public Vector3 ClipBox;
public Vector3 ClipBoxSize;
public Vector3 RevisedValuesPos;
public Vector3 RevisedValuesRot;
public Vector3 RevisedValuesScale;
public Vector3 RevisedValuesColor;
public uint Version;
public uint DrawLayerType;
public uint DrawOrderType;
public uint DirectionalLightSourceType;
public uint PointLightsType1;
public uint PointLightsType2;
public float BiasZmaxScale;
public float BiasZmaxDistance;
public float NearClipBegin;
public float NearClipEnd;
public float FadeInnerX;
public float FadeOuterX;
public float FadeInnerY;
public float FadeOuterY;
public float FadeInnerZ;
public float FadeOuterZ;
public float FarClipBegin;
public float FarClipEnd;
public float SoftParticleFadeRange;
public float SoftKeyOffset;
public float GlobalFogInfluence;
public bool IsDelayFastParticle;
public bool IsFitGround;
public bool IsTransformSkip;
public bool IsAllStopOnHide;
public bool CanBeClippedOut;
public bool ClipBoxEnabled;
public bool IsCameraSpace;
public bool IsFullEnvLight;
public bool IsClipOwnSetting;
public bool FadeEnabledX;
public bool FadeEnabledY;
public bool FadeEnabledZ;
public bool GlobalFogEnabled;
public bool LtsEnabled;
public Block[] Schedulers = Array.Empty<Block>();
public Block[] Timelines = Array.Empty<Block>();
public Block[] Emitters = Array.Empty<Block>();
public Block[] Particles = Array.Empty<Block>();
public Block[] Effectors = Array.Empty<Block>();
public Block[] Binders = Array.Empty<Block>();
public string[] Textures = Array.Empty<string>();
public Block[] Models = Array.Empty<Block>();
public bool Valid { get; } = true;
public AvfxFile(byte[] data)
{
using var stream = new MemoryStream(data);
using var r = new BinaryReader(stream);
var name = r.ReadUInt32();
var size = r.ReadUInt32();
var schedulerCount = 0;
var timelineCount = 0;
var emitterCount = 0;
var particleCount = 0;
var effectorCount = 0;
var binderCount = 0;
var textureCount = 0;
var modelCount = 0;
while (r.BaseStream.Position < size)
{
var block = new Block(r);
switch (block.Name)
{
// @formatter:off
case AvfxMagic.Version: Version = block.ToUint(); break;
case AvfxMagic.IsDelayFastParticle: IsDelayFastParticle = block.ToBool(); break;
case AvfxMagic.IsFitGround: IsFitGround = block.ToBool(); break;
case AvfxMagic.IsTransformSkip: IsTransformSkip = block.ToBool(); break;
case AvfxMagic.IsAllStopOnHide: IsAllStopOnHide = block.ToBool(); break;
case AvfxMagic.CanBeClippedOut: CanBeClippedOut = block.ToBool(); break;
case AvfxMagic.ClipBoxEnabled: ClipBoxEnabled = block.ToBool(); break;
case AvfxMagic.ClipBoxX: ClipBox.X = block.ToFloat(); break;
case AvfxMagic.ClipBoxY: ClipBox.Y = block.ToFloat(); break;
case AvfxMagic.ClipBoxZ: ClipBox.Z = block.ToFloat(); break;
case AvfxMagic.ClipBoxSizeX: ClipBoxSize.X = block.ToFloat(); break;
case AvfxMagic.ClipBoxSizeY: ClipBoxSize.Y = block.ToFloat(); break;
case AvfxMagic.ClipBoxSizeZ: ClipBoxSize.Z = block.ToFloat(); break;
case AvfxMagic.BiasZmaxScale: BiasZmaxScale = block.ToFloat(); break;
case AvfxMagic.BiasZmaxDistance: BiasZmaxDistance = block.ToFloat(); break;
case AvfxMagic.IsCameraSpace: IsCameraSpace = block.ToBool(); break;
case AvfxMagic.IsFullEnvLight: IsFullEnvLight = block.ToBool(); break;
case AvfxMagic.IsClipOwnSetting: IsClipOwnSetting = block.ToBool(); break;
case AvfxMagic.NearClipBegin: NearClipBegin = block.ToFloat(); break;
case AvfxMagic.NearClipEnd: NearClipEnd = block.ToFloat(); break;
case AvfxMagic.FarClipBegin: FarClipBegin = block.ToFloat(); break;
case AvfxMagic.FarClipEnd: FarClipEnd = block.ToFloat(); break;
case AvfxMagic.SoftParticleFadeRange: SoftParticleFadeRange = block.ToFloat(); break;
case AvfxMagic.SoftKeyOffset: SoftKeyOffset = block.ToFloat(); break;
case AvfxMagic.DrawLayerType: DrawLayerType = block.ToUint(); break;
case AvfxMagic.DrawOrderType: DrawOrderType = block.ToUint(); break;
case AvfxMagic.DirectionalLightSourceType: DirectionalLightSourceType = block.ToUint(); break;
case AvfxMagic.PointLightsType1: PointLightsType1 = block.ToUint(); break;
case AvfxMagic.PointLightsType2: PointLightsType2 = block.ToUint(); break;
case AvfxMagic.RevisedValuesPosX: RevisedValuesPos.X = block.ToFloat(); break;
case AvfxMagic.RevisedValuesPosY: RevisedValuesPos.Y = block.ToFloat(); break;
case AvfxMagic.RevisedValuesPosZ: RevisedValuesPos.Z = block.ToFloat(); break;
case AvfxMagic.RevisedValuesRotX: RevisedValuesRot.X = block.ToFloat(); break;
case AvfxMagic.RevisedValuesRotY: RevisedValuesRot.Y = block.ToFloat(); break;
case AvfxMagic.RevisedValuesRotZ: RevisedValuesRot.Z = block.ToFloat(); break;
case AvfxMagic.RevisedValuesScaleX: RevisedValuesScale.X = block.ToFloat(); break;
case AvfxMagic.RevisedValuesScaleY: RevisedValuesScale.Y = block.ToFloat(); break;
case AvfxMagic.RevisedValuesScaleZ: RevisedValuesScale.Z = block.ToFloat(); break;
case AvfxMagic.RevisedValuesColorR: RevisedValuesColor.X = block.ToFloat(); break;
case AvfxMagic.RevisedValuesColorG: RevisedValuesColor.Y = block.ToFloat(); break;
case AvfxMagic.RevisedValuesColorB: RevisedValuesColor.Z = block.ToFloat(); break;
case AvfxMagic.FadeEnabledX: FadeEnabledX = block.ToBool(); break;
case AvfxMagic.FadeInnerX: FadeInnerX = block.ToFloat(); break;
case AvfxMagic.FadeOuterX: FadeOuterX = block.ToFloat(); break;
case AvfxMagic.FadeEnabledY: FadeEnabledY = block.ToBool(); break;
case AvfxMagic.FadeInnerY: FadeInnerY = block.ToFloat(); break;
case AvfxMagic.FadeOuterY: FadeOuterY = block.ToFloat(); break;
case AvfxMagic.FadeEnabledZ: FadeEnabledZ = block.ToBool(); break;
case AvfxMagic.FadeInnerZ: FadeInnerZ = block.ToFloat(); break;
case AvfxMagic.FadeOuterZ: FadeOuterZ = block.ToFloat(); break;
case AvfxMagic.GlobalFogEnabled: GlobalFogEnabled = block.ToBool(); break;
case AvfxMagic.GlobalFogInfluence: GlobalFogInfluence = block.ToFloat(); break;
case AvfxMagic.LtsEnabled: LtsEnabled = block.ToBool(); break;
case AvfxMagic.NumSchedulers: Schedulers = new Block[block.ToUint()]; break;
case AvfxMagic.NumTimelines: Timelines = new Block[block.ToUint()]; break;
case AvfxMagic.NumEmitters: Emitters = new Block[block.ToUint()]; break;
case AvfxMagic.NumParticles: Particles = new Block[block.ToUint()]; break;
case AvfxMagic.NumEffectors: Effectors = new Block[block.ToUint()]; break;
case AvfxMagic.NumBinders: Binders = new Block[block.ToUint()]; break;
case AvfxMagic.NumTextures: Textures = new string[block.ToUint()]; break;
case AvfxMagic.NumModels: Models = new Block[block.ToUint()]; break;
case AvfxMagic.Scheduler: Schedulers[schedulerCount++] = block; break;
case AvfxMagic.Timeline: Timelines[timelineCount++] = block; break;
case AvfxMagic.Emitter: Emitters[emitterCount++] = block; break;
case AvfxMagic.Particle: Particles[particleCount++] = block; break;
case AvfxMagic.Effector: Effectors[effectorCount++] = block; break;
case AvfxMagic.Binder: Binders[binderCount++] = block; break;
case AvfxMagic.Texture: Textures[textureCount++] = block.ToString(); break;
case AvfxMagic.Model: Models[modelCount++] = block; break;
// @formatter:on
}
}
}
public byte[] Write()
{
using var m = new MemoryStream(512 * 1024);
using var w = new BinaryWriter(m);
w.Write(AvfxMagic.AvfxBase);
var sizePos = w.BaseStream.Position;
w.Write(0u);
w.WriteBlock(AvfxMagic.Version, Version)
.WriteBlock(AvfxMagic.IsDelayFastParticle, IsDelayFastParticle)
.WriteBlock(AvfxMagic.IsDelayFastParticle, IsDelayFastParticle)
.WriteBlock(AvfxMagic.IsFitGround, IsFitGround)
.WriteBlock(AvfxMagic.IsTransformSkip, IsTransformSkip)
.WriteBlock(AvfxMagic.IsAllStopOnHide, IsAllStopOnHide)
.WriteBlock(AvfxMagic.CanBeClippedOut, CanBeClippedOut)
.WriteBlock(AvfxMagic.ClipBoxEnabled, ClipBoxEnabled)
.WriteBlock(AvfxMagic.ClipBoxX, ClipBox.X)
.WriteBlock(AvfxMagic.ClipBoxY, ClipBox.Y)
.WriteBlock(AvfxMagic.ClipBoxZ, ClipBox.Z)
.WriteBlock(AvfxMagic.ClipBoxSizeX, ClipBoxSize.X)
.WriteBlock(AvfxMagic.ClipBoxSizeY, ClipBoxSize.Y)
.WriteBlock(AvfxMagic.ClipBoxSizeZ, ClipBoxSize.Z)
.WriteBlock(AvfxMagic.BiasZmaxScale, BiasZmaxScale)
.WriteBlock(AvfxMagic.BiasZmaxDistance, BiasZmaxDistance)
.WriteBlock(AvfxMagic.IsCameraSpace, IsCameraSpace)
.WriteBlock(AvfxMagic.IsFullEnvLight, IsFullEnvLight)
.WriteBlock(AvfxMagic.IsClipOwnSetting, IsClipOwnSetting)
.WriteBlock(AvfxMagic.NearClipBegin, NearClipBegin)
.WriteBlock(AvfxMagic.NearClipEnd, NearClipEnd)
.WriteBlock(AvfxMagic.FarClipBegin, FarClipBegin)
.WriteBlock(AvfxMagic.FarClipEnd, FarClipEnd)
.WriteBlock(AvfxMagic.SoftParticleFadeRange, SoftParticleFadeRange)
.WriteBlock(AvfxMagic.SoftKeyOffset, SoftKeyOffset)
.WriteBlock(AvfxMagic.DrawLayerType, DrawLayerType)
.WriteBlock(AvfxMagic.DrawOrderType, DrawOrderType)
.WriteBlock(AvfxMagic.DirectionalLightSourceType, DirectionalLightSourceType)
.WriteBlock(AvfxMagic.PointLightsType1, PointLightsType1)
.WriteBlock(AvfxMagic.PointLightsType2, PointLightsType2)
.WriteBlock(AvfxMagic.RevisedValuesPosX, RevisedValuesPos.X)
.WriteBlock(AvfxMagic.RevisedValuesPosY, RevisedValuesPos.Y)
.WriteBlock(AvfxMagic.RevisedValuesPosZ, RevisedValuesPos.Z)
.WriteBlock(AvfxMagic.RevisedValuesRotX, RevisedValuesRot.X)
.WriteBlock(AvfxMagic.RevisedValuesRotY, RevisedValuesRot.Y)
.WriteBlock(AvfxMagic.RevisedValuesRotZ, RevisedValuesRot.Z)
.WriteBlock(AvfxMagic.RevisedValuesScaleX, RevisedValuesScale.X)
.WriteBlock(AvfxMagic.RevisedValuesScaleY, RevisedValuesScale.Y)
.WriteBlock(AvfxMagic.RevisedValuesScaleZ, RevisedValuesScale.Z)
.WriteBlock(AvfxMagic.RevisedValuesColorR, RevisedValuesColor.X)
.WriteBlock(AvfxMagic.RevisedValuesColorG, RevisedValuesColor.Y)
.WriteBlock(AvfxMagic.RevisedValuesColorB, RevisedValuesColor.Z)
.WriteBlock(AvfxMagic.FadeEnabledX, FadeEnabledX)
.WriteBlock(AvfxMagic.FadeInnerX, FadeInnerX)
.WriteBlock(AvfxMagic.FadeOuterX, FadeOuterX)
.WriteBlock(AvfxMagic.FadeEnabledY, FadeEnabledY)
.WriteBlock(AvfxMagic.FadeInnerY, FadeInnerY)
.WriteBlock(AvfxMagic.FadeOuterY, FadeOuterY)
.WriteBlock(AvfxMagic.FadeEnabledZ, FadeEnabledZ)
.WriteBlock(AvfxMagic.FadeInnerZ, FadeInnerZ)
.WriteBlock(AvfxMagic.FadeOuterZ, FadeOuterZ)
.WriteBlock(AvfxMagic.GlobalFogEnabled, GlobalFogEnabled)
.WriteBlock(AvfxMagic.GlobalFogInfluence, GlobalFogInfluence)
.WriteBlock(AvfxMagic.LtsEnabled, LtsEnabled)
.WriteBlock(AvfxMagic.NumSchedulers, (uint)Schedulers.Length)
.WriteBlock(AvfxMagic.NumTimelines, (uint)Timelines.Length)
.WriteBlock(AvfxMagic.NumEmitters, (uint)Emitters.Length)
.WriteBlock(AvfxMagic.NumParticles, (uint)Particles.Length)
.WriteBlock(AvfxMagic.NumEffectors, (uint)Effectors.Length)
.WriteBlock(AvfxMagic.NumBinders, (uint)Binders.Length)
.WriteBlock(AvfxMagic.NumTextures, (uint)Textures.Length)
.WriteBlock(AvfxMagic.NumModels, (uint)Models.Length);
foreach (var block in Schedulers)
w.WriteBlock(block);
foreach (var block in Timelines)
w.WriteBlock(block);
foreach (var block in Emitters)
w.WriteBlock(block);
foreach (var block in Particles)
w.WriteBlock(block);
foreach (var block in Effectors)
w.WriteBlock(block);
foreach (var block in Binders)
w.WriteBlock(block);
foreach (var texture in Textures)
w.WriteTextureBlock(texture);
foreach (var block in Models)
w.WriteBlock(block);
w.Seek((int)sizePos, SeekOrigin.Begin);
w.Write((uint)w.BaseStream.Length);
return m.ToArray();
}
}

View file

@ -0,0 +1,137 @@
using System.IO;
using System.Numerics;
using System.Text;
// ReSharper disable ShiftExpressionZeroLeftOperand
namespace Penumbra.GameData.Files;
public static class AvfxMagic
{
public const uint AvfxBase = ('A' << 24) | ('V' << 16) | ('F' << 8) | (uint)'X';
public const uint Version = (000 << 24) | ('V' << 16) | ('e' << 8) | (uint)'r';
public const uint IsDelayFastParticle = ('b' << 24) | ('D' << 16) | ('F' << 8) | (uint)'P';
public const uint IsFitGround = (000 << 24) | ('b' << 16) | ('F' << 8) | (uint)'G';
public const uint IsTransformSkip = (000 << 24) | ('b' << 16) | ('T' << 8) | (uint)'S';
public const uint IsAllStopOnHide = ('b' << 24) | ('A' << 16) | ('S' << 8) | (uint)'H';
public const uint CanBeClippedOut = ('b' << 24) | ('C' << 16) | ('B' << 8) | (uint)'C';
public const uint ClipBoxEnabled = ('b' << 24) | ('C' << 16) | ('u' << 8) | (uint)'l';
public const uint ClipBoxX = ('C' << 24) | ('B' << 16) | ('P' << 8) | (uint)'x';
public const uint ClipBoxY = ('C' << 24) | ('B' << 16) | ('P' << 8) | (uint)'y';
public const uint ClipBoxZ = ('C' << 24) | ('B' << 16) | ('P' << 8) | (uint)'z';
public const uint ClipBoxSizeX = ('C' << 24) | ('B' << 16) | ('S' << 8) | (uint)'x';
public const uint ClipBoxSizeY = ('C' << 24) | ('B' << 16) | ('S' << 8) | (uint)'y';
public const uint ClipBoxSizeZ = ('C' << 24) | ('B' << 16) | ('S' << 8) | (uint)'z';
public const uint BiasZmaxScale = ('Z' << 24) | ('B' << 16) | ('M' << 8) | (uint)'s';
public const uint BiasZmaxDistance = ('Z' << 24) | ('B' << 16) | ('M' << 8) | (uint)'d';
public const uint IsCameraSpace = ('b' << 24) | ('C' << 16) | ('m' << 8) | (uint)'S';
public const uint IsFullEnvLight = ('b' << 24) | ('F' << 16) | ('E' << 8) | (uint)'L';
public const uint IsClipOwnSetting = ('b' << 24) | ('O' << 16) | ('S' << 8) | (uint)'t';
public const uint NearClipBegin = (000 << 24) | ('N' << 16) | ('C' << 8) | (uint)'B';
public const uint NearClipEnd = (000 << 24) | ('N' << 16) | ('C' << 8) | (uint)'E';
public const uint FarClipBegin = (000 << 24) | ('F' << 16) | ('C' << 8) | (uint)'B';
public const uint FarClipEnd = (000 << 24) | ('F' << 16) | ('C' << 8) | (uint)'E';
public const uint SoftParticleFadeRange = ('S' << 24) | ('P' << 16) | ('F' << 8) | (uint)'R';
public const uint SoftKeyOffset = (000 << 24) | ('S' << 16) | ('K' << 8) | (uint)'O';
public const uint DrawLayerType = ('D' << 24) | ('w' << 16) | ('L' << 8) | (uint)'y';
public const uint DrawOrderType = ('D' << 24) | ('w' << 16) | ('O' << 8) | (uint)'T';
public const uint DirectionalLightSourceType = ('D' << 24) | ('L' << 16) | ('S' << 8) | (uint)'T';
public const uint PointLightsType1 = ('P' << 24) | ('L' << 16) | ('1' << 8) | (uint)'S';
public const uint PointLightsType2 = ('P' << 24) | ('L' << 16) | ('2' << 8) | (uint)'S';
public const uint RevisedValuesPosX = ('R' << 24) | ('v' << 16) | ('P' << 8) | (uint)'x';
public const uint RevisedValuesPosY = ('R' << 24) | ('v' << 16) | ('P' << 8) | (uint)'y';
public const uint RevisedValuesPosZ = ('R' << 24) | ('v' << 16) | ('P' << 8) | (uint)'z';
public const uint RevisedValuesRotX = ('R' << 24) | ('v' << 16) | ('R' << 8) | (uint)'x';
public const uint RevisedValuesRotY = ('R' << 24) | ('v' << 16) | ('R' << 8) | (uint)'y';
public const uint RevisedValuesRotZ = ('R' << 24) | ('v' << 16) | ('R' << 8) | (uint)'z';
public const uint RevisedValuesScaleX = ('R' << 24) | ('v' << 16) | ('S' << 8) | (uint)'x';
public const uint RevisedValuesScaleY = ('R' << 24) | ('v' << 16) | ('S' << 8) | (uint)'y';
public const uint RevisedValuesScaleZ = ('R' << 24) | ('v' << 16) | ('S' << 8) | (uint)'z';
public const uint RevisedValuesColorR = (000 << 24) | ('R' << 16) | ('v' << 8) | (uint)'R';
public const uint RevisedValuesColorG = (000 << 24) | ('R' << 16) | ('v' << 8) | (uint)'G';
public const uint RevisedValuesColorB = (000 << 24) | ('R' << 16) | ('v' << 8) | (uint)'B';
public const uint FadeEnabledX = ('A' << 24) | ('F' << 16) | ('X' << 8) | (uint)'e';
public const uint FadeInnerX = ('A' << 24) | ('F' << 16) | ('X' << 8) | (uint)'i';
public const uint FadeOuterX = ('A' << 24) | ('F' << 16) | ('X' << 8) | (uint)'o';
public const uint FadeEnabledY = ('A' << 24) | ('F' << 16) | ('Y' << 8) | (uint)'e';
public const uint FadeInnerY = ('A' << 24) | ('F' << 16) | ('Y' << 8) | (uint)'i';
public const uint FadeOuterY = ('A' << 24) | ('F' << 16) | ('Y' << 8) | (uint)'o';
public const uint FadeEnabledZ = ('A' << 24) | ('F' << 16) | ('Z' << 8) | (uint)'e';
public const uint FadeInnerZ = ('A' << 24) | ('F' << 16) | ('Z' << 8) | (uint)'i';
public const uint FadeOuterZ = ('A' << 24) | ('F' << 16) | ('Z' << 8) | (uint)'o';
public const uint GlobalFogEnabled = ('b' << 24) | ('G' << 16) | ('F' << 8) | (uint)'E';
public const uint GlobalFogInfluence = ('G' << 24) | ('F' << 16) | ('I' << 8) | (uint)'M';
public const uint LtsEnabled = ('b' << 24) | ('L' << 16) | ('T' << 8) | (uint)'S';
public const uint NumSchedulers = ('S' << 24) | ('c' << 16) | ('C' << 8) | (uint)'n';
public const uint NumTimelines = ('T' << 24) | ('l' << 16) | ('C' << 8) | (uint)'n';
public const uint NumEmitters = ('E' << 24) | ('m' << 16) | ('C' << 8) | (uint)'n';
public const uint NumParticles = ('P' << 24) | ('r' << 16) | ('C' << 8) | (uint)'n';
public const uint NumEffectors = ('E' << 24) | ('f' << 16) | ('C' << 8) | (uint)'n';
public const uint NumBinders = ('B' << 24) | ('d' << 16) | ('C' << 8) | (uint)'n';
public const uint NumTextures = ('T' << 24) | ('x' << 16) | ('C' << 8) | (uint)'n';
public const uint NumModels = ('M' << 24) | ('d' << 16) | ('C' << 8) | (uint)'n';
public const uint Scheduler = ('S' << 24) | ('c' << 16) | ('h' << 8) | (uint)'d';
public const uint Timeline = ('T' << 24) | ('m' << 16) | ('L' << 8) | (uint)'n';
public const uint Emitter = ('E' << 24) | ('m' << 16) | ('i' << 8) | (uint)'t';
public const uint Particle = ('P' << 24) | ('t' << 16) | ('c' << 8) | (uint)'l';
public const uint Effector = ('E' << 24) | ('f' << 16) | ('c' << 8) | (uint)'t';
public const uint Binder = ('B' << 24) | ('i' << 16) | ('n' << 8) | (uint)'d';
public const uint Texture = (000 << 24) | ('T' << 16) | ('e' << 8) | (uint)'x';
public const uint Model = ('M' << 24) | ('o' << 16) | ('d' << 8) | (uint)'l';
internal static uint RoundTo4(this uint size)
{
var rest = size & 0b11u;
return rest > 0 ? (size & ~0b11u) + 4u : size;
}
internal static BinaryWriter WriteTextureBlock(this BinaryWriter bw, string texture)
{
bw.Write(Texture);
var bytes = Encoding.UTF8.GetBytes(texture);
var size = (uint)bytes.Length + 1u;
bw.Write(size);
bw.Write(bytes);
bw.Write((byte)0);
for (var end = size.RoundTo4(); size < end; ++size)
bw.Write((byte)0);
return bw;
}
internal static BinaryWriter WriteBlock(this BinaryWriter bw, AvfxFile.Block block)
{
bw.Write(block.Name);
bw.Write(block.Size);
bw.Write(block.Data);
return bw;
}
internal static BinaryWriter WriteBlock(this BinaryWriter bw, uint magic, uint value)
{
bw.Write(magic);
bw.Write(4u);
bw.Write(value);
return bw;
}
internal static BinaryWriter WriteBlock(this BinaryWriter bw, uint magic, bool value)
{
bw.Write(magic);
bw.Write(4u);
bw.Write(value ? 1u : 0u);
return bw;
}
internal static BinaryWriter WriteBlock(this BinaryWriter bw, uint magic, float value)
{
bw.Write(magic);
bw.Write(4u);
bw.Write(value);
return bw;
}
internal static BinaryWriter WriteBlock(this BinaryWriter bw, uint magicX, uint magicY, uint magicZ, Vector3 value)
=> bw.WriteBlock(magicX, value.X)
.WriteBlock(magicY, value.Y)
.WriteBlock(magicZ, value.Z);
}