mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2025-01-09 23:15:09 +08:00
Merge branch 'master' of https://github.com/dexyfex/CodeWalker
This commit is contained in:
commit
77d18307fa
@ -2673,11 +2673,12 @@ namespace CodeWalker.GameFiles
|
||||
MinRepeatTime = br.ReadInt16();
|
||||
VariableCount = br.ReadByte();
|
||||
VariableNames = new MetaHash[VariableCount];
|
||||
VariableValues = new byte[VariableCount];
|
||||
for (int i = 0; i < VariableCount; i++)
|
||||
{
|
||||
VariableNames[i] = br.ReadUInt32();
|
||||
VariableValues[i] = br.ReadByte();
|
||||
}
|
||||
VariableValues = br.ReadBytes(VariableCount);
|
||||
|
||||
ChildSoundsHashes = new[] { ChildSound, FallBackSound };
|
||||
}
|
||||
@ -2743,13 +2744,8 @@ namespace CodeWalker.GameFiles
|
||||
for (int i = 0; i < VariableCount; i++)
|
||||
{
|
||||
bw.Write(VariableNames[i]);
|
||||
bw.Write(VariableValues[i]);
|
||||
}
|
||||
if (VariableValues != null)
|
||||
{
|
||||
bw.Write(VariableValues);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
public override uint[] GetHashTableOffsets()
|
||||
{
|
||||
|
270
CodeWalker.Core/GameFiles/FileTypes/YpdbFile.cs
Normal file
270
CodeWalker.Core/GameFiles/FileTypes/YpdbFile.cs
Normal file
@ -0,0 +1,270 @@
|
||||
using SharpDX;
|
||||
using System.IO;
|
||||
using TC = System.ComponentModel.TypeConverterAttribute;
|
||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
public class YpdbFile : GameFile, PackedFile
|
||||
{
|
||||
public int SerializerVersion { get; set; } // 2
|
||||
public int PoseMatcherVersion { get; set; } // 0
|
||||
public uint Signature { get; set; }
|
||||
public int SamplesCount { get; set; }
|
||||
public PoseMatcherMatchSample[] Samples { get; set; }
|
||||
public int BoneTagsCount { get; set; }
|
||||
public ushort[] BoneTags { get; set; }
|
||||
public PoseMatcherWeightSet WeightSet { get; set; }
|
||||
public float Unk7 { get; set; } // 0.033333f
|
||||
public int Unk8 { get; set; } // 1
|
||||
|
||||
public YpdbFile() : base(null, GameFileType.Ypdb)
|
||||
{
|
||||
}
|
||||
public YpdbFile(RpfFileEntry entry) : base(entry, GameFileType.Ypdb)
|
||||
{
|
||||
}
|
||||
|
||||
public void Load(byte[] data, RpfFileEntry entry)
|
||||
{
|
||||
if (entry != null)
|
||||
{
|
||||
RpfFileEntry = entry;
|
||||
Name = entry.Name;
|
||||
}
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(data))
|
||||
{
|
||||
DataReader r = new DataReader(ms, Endianess.LittleEndian);
|
||||
|
||||
Read(r);
|
||||
}
|
||||
|
||||
Loaded = true;
|
||||
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
MemoryStream s = new MemoryStream();
|
||||
DataWriter w = new DataWriter(s);
|
||||
|
||||
Write(w);
|
||||
|
||||
var buf = new byte[s.Length];
|
||||
s.Position = 0;
|
||||
s.Read(buf, 0, buf.Length);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private void Read(DataReader r)
|
||||
{
|
||||
byte magic = r.ReadByte();
|
||||
if (magic != 0x1A) // 0x1A indicates to the game deserializer that it's binary instead of text
|
||||
{ } // no hit
|
||||
|
||||
SerializerVersion = r.ReadInt32();
|
||||
PoseMatcherVersion = r.ReadInt32();
|
||||
Signature = r.ReadUInt32();
|
||||
|
||||
SamplesCount = r.ReadInt32();
|
||||
if (SamplesCount > 0)
|
||||
{
|
||||
Samples = new PoseMatcherMatchSample[SamplesCount];
|
||||
|
||||
for (int i = 0; i < SamplesCount; i++)
|
||||
Samples[i] = new PoseMatcherMatchSample(r);
|
||||
}
|
||||
|
||||
BoneTagsCount = r.ReadInt32();
|
||||
if (BoneTagsCount > 0)
|
||||
{
|
||||
BoneTags = new ushort[BoneTagsCount];
|
||||
|
||||
for (int i = 0; i < BoneTagsCount; i++)
|
||||
BoneTags[i] = r.ReadUInt16();
|
||||
}
|
||||
|
||||
WeightSet = new PoseMatcherWeightSet(r);
|
||||
|
||||
Unk7 = r.ReadSingle();
|
||||
Unk8 = r.ReadInt32();
|
||||
|
||||
uint signature2 = r.ReadUInt32();
|
||||
|
||||
if (SerializerVersion != 2)
|
||||
{ } // no hit
|
||||
if (PoseMatcherVersion != 0)
|
||||
{ } // no hit
|
||||
if (BoneTagsCount != WeightSet.WeightsCount)
|
||||
{ } // no hit
|
||||
if (Unk7 != 0.033333f)
|
||||
{ } // no hit
|
||||
if (Unk8 != 1)
|
||||
{ } // no hit
|
||||
if (Signature != signature2)
|
||||
{ } // no hit
|
||||
|
||||
if (r.Position != r.Length)
|
||||
{ }
|
||||
}
|
||||
|
||||
private void Write(DataWriter w)
|
||||
{
|
||||
w.Write((byte)0x1A);
|
||||
w.Write(SerializerVersion);
|
||||
w.Write(PoseMatcherVersion);
|
||||
w.Write(Signature);
|
||||
|
||||
w.Write(SamplesCount);
|
||||
if (SamplesCount > 0)
|
||||
{
|
||||
foreach (var entry in Samples)
|
||||
entry.Write(w);
|
||||
}
|
||||
|
||||
w.Write(BoneTagsCount);
|
||||
if (BoneTagsCount > 0)
|
||||
{
|
||||
foreach (var boneTag in BoneTags)
|
||||
w.Write(boneTag);
|
||||
}
|
||||
|
||||
WeightSet.Write(w);
|
||||
|
||||
w.Write(Unk7);
|
||||
w.Write(Unk8);
|
||||
|
||||
w.Write(Signature);
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))]
|
||||
public class PoseMatcherMatchSample
|
||||
{
|
||||
// rage::crPoseMatcherData::MatchSample
|
||||
public MetaHash ClipSet { get; set; } // from clip_sets.ymt/xml
|
||||
public MetaHash Clip { get; set; }
|
||||
public float Unk3 { get; set; }
|
||||
public PoseMatcherPointCloud PointCloud { get; set; }
|
||||
|
||||
public PoseMatcherMatchSample(DataReader r)
|
||||
{
|
||||
ClipSet = r.ReadUInt32();
|
||||
Clip = r.ReadUInt32();
|
||||
|
||||
Unk3 = r.ReadSingle();
|
||||
|
||||
PointCloud = new PoseMatcherPointCloud(r);
|
||||
}
|
||||
|
||||
public void Write(DataWriter w)
|
||||
{
|
||||
w.Write(ClipSet);
|
||||
w.Write(Clip);
|
||||
|
||||
w.Write(Unk3);
|
||||
|
||||
PointCloud.Write(w);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ClipSet}, {Clip}";
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))]
|
||||
public class PoseMatcherPointCloud
|
||||
{
|
||||
// rage::crpmPointCloud
|
||||
public int PointsCount { get; set; }
|
||||
public Vector3[] Points { get; set; }
|
||||
public int Unk2_Count { get; set; } // == PointsCount
|
||||
public float[] Unk2_Items { get; set; }
|
||||
public Vector3 BoundsMin { get; set; }
|
||||
public Vector3 BoundsMax { get; set; }
|
||||
public float Unk5 { get; set; }
|
||||
|
||||
public PoseMatcherPointCloud(DataReader r)
|
||||
{
|
||||
PointsCount = r.ReadInt32();
|
||||
if (PointsCount > 0)
|
||||
{
|
||||
Points = new Vector3[PointsCount];
|
||||
|
||||
for (int i = 0; i < PointsCount; i++)
|
||||
Points[i] = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
}
|
||||
|
||||
Unk2_Count = r.ReadInt32();
|
||||
if (Unk2_Count > 0)
|
||||
{
|
||||
Unk2_Items = new float[Unk2_Count];
|
||||
|
||||
for (int i = 0; i < Unk2_Count; i++)
|
||||
Unk2_Items[i] = r.ReadSingle();
|
||||
}
|
||||
|
||||
BoundsMin = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
BoundsMax = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
|
||||
|
||||
Unk5 = r.ReadSingle();
|
||||
|
||||
if (PointsCount != Unk2_Count)
|
||||
{ } // no hit
|
||||
}
|
||||
|
||||
public void Write(DataWriter w)
|
||||
{
|
||||
w.Write(PointsCount);
|
||||
if (PointsCount > 0)
|
||||
{
|
||||
foreach (var point in Points)
|
||||
w.Write(point);
|
||||
}
|
||||
|
||||
w.Write(Unk2_Count);
|
||||
if (Unk2_Count > 0)
|
||||
{
|
||||
foreach (var entry in Unk2_Items)
|
||||
w.Write(entry);
|
||||
}
|
||||
|
||||
w.Write(BoundsMin);
|
||||
w.Write(BoundsMax);
|
||||
|
||||
w.Write(Unk5);
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))]
|
||||
public class PoseMatcherWeightSet
|
||||
{
|
||||
// rage::crWeightSet
|
||||
public int WeightsCount { get; set; }
|
||||
public float[] Weights { get; set; }
|
||||
|
||||
public PoseMatcherWeightSet(DataReader r)
|
||||
{
|
||||
WeightsCount = r.ReadInt32();
|
||||
if (WeightsCount > 0)
|
||||
{
|
||||
Weights = new float[WeightsCount];
|
||||
|
||||
for (int i = 0; i < WeightsCount; i++)
|
||||
Weights[i] = r.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(DataWriter w)
|
||||
{
|
||||
w.Write(WeightsCount);
|
||||
if (WeightsCount > 0)
|
||||
{
|
||||
foreach (var weight in Weights)
|
||||
w.Write(weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -84,6 +84,7 @@ namespace CodeWalker.GameFiles
|
||||
Watermap = 28,
|
||||
Mrf = 29,
|
||||
DistantLights = 30,
|
||||
Ypdb = 31,
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,6 +215,7 @@ namespace CodeWalker.GameFiles
|
||||
//TestYvrs();
|
||||
//TestYwrs();
|
||||
//TestYmaps();
|
||||
//TestYpdbs();
|
||||
//TestMrfs();
|
||||
//TestPlacements();
|
||||
//TestDrawables();
|
||||
@ -4526,6 +4527,48 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
}
|
||||
public void TestYpdbs()
|
||||
{
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
{
|
||||
foreach (RpfEntry entry in file.AllEntries)
|
||||
{
|
||||
var rfe = entry as RpfFileEntry;
|
||||
if (rfe == null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (rfe.NameLower.EndsWith(".ypdb"))
|
||||
{
|
||||
UpdateStatus(string.Format(entry.Path));
|
||||
YpdbFile ypdb = RpfMan.GetFile<YpdbFile>(entry);
|
||||
if (ypdb != null)
|
||||
{
|
||||
var odata = entry.File.ExtractFile(entry as RpfFileEntry);
|
||||
var ndata = ypdb.Save();
|
||||
if (ndata.Length == odata.Length)
|
||||
{
|
||||
for (int i = 0; i < ndata.Length; i++)
|
||||
{
|
||||
if (ndata[i] != odata[i])
|
||||
{ break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus("Error! " + ex.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
public void TestMrfs()
|
||||
{
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
|
@ -309,6 +309,7 @@ namespace CodeWalker
|
||||
InitFileType(".awc", "Audio Wave Container", 22, FileTypeAction.ViewAwc, true);
|
||||
InitFileType(".rel", "Audio Data (REL)", 23, FileTypeAction.ViewRel, true);
|
||||
InitFileType(".nametable", "Name Table", 5, FileTypeAction.ViewNametable);
|
||||
InitFileType(".ypdb", "Pose Matcher Database", 9, FileTypeAction.ViewYpdb);
|
||||
|
||||
InitSubFileType(".dat", "cache_y.dat", "Cache File", 6, FileTypeAction.ViewCacheDat, true);
|
||||
InitSubFileType(".dat", "heightmap.dat", "Heightmap", 6, FileTypeAction.ViewHeightmap, true);
|
||||
@ -1545,6 +1546,9 @@ namespace CodeWalker
|
||||
case FileTypeAction.ViewDistantLights:
|
||||
ViewDistantLights(name, path, data, fe);
|
||||
break;
|
||||
case FileTypeAction.ViewYpdb:
|
||||
ViewYpdb(name, path, data, fe);
|
||||
break;
|
||||
case FileTypeAction.ViewHex:
|
||||
default:
|
||||
ViewHex(name, path, data);
|
||||
@ -1806,6 +1810,13 @@ namespace CodeWalker
|
||||
f.Show();
|
||||
f.LoadFile(dlf, dlf.RpfFileEntry);
|
||||
}
|
||||
private void ViewYpdb(string name, string path, byte[] data, RpfFileEntry e)
|
||||
{
|
||||
var ypdb = RpfFile.GetFile<YpdbFile>(e, data);
|
||||
GenericForm f = new GenericForm(this);
|
||||
f.Show();
|
||||
f.LoadFile(ypdb, ypdb.RpfFileEntry);
|
||||
}
|
||||
|
||||
private RpfFileEntry CreateFileEntry(string name, string path, ref byte[] data)
|
||||
{
|
||||
@ -4878,6 +4889,7 @@ namespace CodeWalker
|
||||
ViewMrf = 24,
|
||||
ViewNametable = 25,
|
||||
ViewDistantLights = 26,
|
||||
ViewYpdb = 27,
|
||||
}
|
||||
|
||||
|
||||
|
38
CodeWalker/Forms/ModelLightForm.Designer.cs
generated
38
CodeWalker/Forms/ModelLightForm.Designer.cs
generated
@ -30,6 +30,7 @@
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ModelLightForm));
|
||||
this.MainSplitContainer = new System.Windows.Forms.SplitContainer();
|
||||
this.DuplicateLightButton = new System.Windows.Forms.Button();
|
||||
this.DeleteLightButton = new System.Windows.Forms.Button();
|
||||
this.NewLightButton = new System.Windows.Forms.Button();
|
||||
this.LightsTreeView = new CodeWalker.WinForms.TreeViewFix();
|
||||
@ -113,6 +114,7 @@
|
||||
this.EditMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.EditNewLightMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.EditDeleteLightMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.EditDuplicateLightMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OptionsMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.OptionsShowOutlinesMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MoveMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@ -148,6 +150,7 @@
|
||||
//
|
||||
// MainSplitContainer.Panel1
|
||||
//
|
||||
this.MainSplitContainer.Panel1.Controls.Add(this.DuplicateLightButton);
|
||||
this.MainSplitContainer.Panel1.Controls.Add(this.DeleteLightButton);
|
||||
this.MainSplitContainer.Panel1.Controls.Add(this.NewLightButton);
|
||||
this.MainSplitContainer.Panel1.Controls.Add(this.LightsTreeView);
|
||||
@ -155,10 +158,22 @@
|
||||
// MainSplitContainer.Panel2
|
||||
//
|
||||
this.MainSplitContainer.Panel2.Controls.Add(this.LightPropertiesPanel);
|
||||
this.MainSplitContainer.Size = new System.Drawing.Size(733, 523);
|
||||
this.MainSplitContainer.Panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.MainSplitContainer_Panel2_Paint);
|
||||
this.MainSplitContainer.Size = new System.Drawing.Size(733, 561);
|
||||
this.MainSplitContainer.SplitterDistance = 184;
|
||||
this.MainSplitContainer.TabIndex = 0;
|
||||
//
|
||||
// DuplicateLightButton
|
||||
//
|
||||
this.DuplicateLightButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.DuplicateLightButton.Location = new System.Drawing.Point(7, 526);
|
||||
this.DuplicateLightButton.Name = "DuplicateLightButton";
|
||||
this.DuplicateLightButton.Size = new System.Drawing.Size(169, 23);
|
||||
this.DuplicateLightButton.TabIndex = 8;
|
||||
this.DuplicateLightButton.Text = "Duplicate Light";
|
||||
this.DuplicateLightButton.UseVisualStyleBackColor = true;
|
||||
this.DuplicateLightButton.Click += new System.EventHandler(this.DuplicateLightButton_Click);
|
||||
//
|
||||
// DeleteLightButton
|
||||
//
|
||||
this.DeleteLightButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
@ -279,7 +294,7 @@
|
||||
this.LightPropertiesPanel.Controls.Add(this.label31);
|
||||
this.LightPropertiesPanel.Location = new System.Drawing.Point(4, 3);
|
||||
this.LightPropertiesPanel.Name = "LightPropertiesPanel";
|
||||
this.LightPropertiesPanel.Size = new System.Drawing.Size(538, 517);
|
||||
this.LightPropertiesPanel.Size = new System.Drawing.Size(529, 517);
|
||||
this.LightPropertiesPanel.TabIndex = 1;
|
||||
//
|
||||
// VolumetricFadeDistanceUpDown
|
||||
@ -1127,7 +1142,8 @@
|
||||
//
|
||||
this.EditMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.EditNewLightMenu,
|
||||
this.EditDeleteLightMenu});
|
||||
this.EditDeleteLightMenu,
|
||||
this.EditDuplicateLightMenu});
|
||||
this.EditMenu.Name = "EditMenu";
|
||||
this.EditMenu.Size = new System.Drawing.Size(39, 20);
|
||||
this.EditMenu.Text = "Edit";
|
||||
@ -1135,7 +1151,7 @@
|
||||
// EditNewLightMenu
|
||||
//
|
||||
this.EditNewLightMenu.Name = "EditNewLightMenu";
|
||||
this.EditNewLightMenu.Size = new System.Drawing.Size(180, 22);
|
||||
this.EditNewLightMenu.Size = new System.Drawing.Size(154, 22);
|
||||
this.EditNewLightMenu.Text = "New Light";
|
||||
this.EditNewLightMenu.Click += new System.EventHandler(this.EditNewLightMenu_Click);
|
||||
//
|
||||
@ -1143,10 +1159,18 @@
|
||||
//
|
||||
this.EditDeleteLightMenu.Enabled = false;
|
||||
this.EditDeleteLightMenu.Name = "EditDeleteLightMenu";
|
||||
this.EditDeleteLightMenu.Size = new System.Drawing.Size(180, 22);
|
||||
this.EditDeleteLightMenu.Size = new System.Drawing.Size(154, 22);
|
||||
this.EditDeleteLightMenu.Text = "Delete Light";
|
||||
this.EditDeleteLightMenu.Click += new System.EventHandler(this.EditDeleteLightMenu_Click);
|
||||
//
|
||||
// EditDuplicateLightMenu
|
||||
//
|
||||
this.EditDuplicateLightMenu.Enabled = false;
|
||||
this.EditDuplicateLightMenu.Name = "EditDuplicateLightMenu";
|
||||
this.EditDuplicateLightMenu.Size = new System.Drawing.Size(154, 22);
|
||||
this.EditDuplicateLightMenu.Text = "Duplicate Light";
|
||||
this.EditDuplicateLightMenu.Click += new System.EventHandler(this.EditDuplicateLightMenu_Click);
|
||||
//
|
||||
// OptionsMenu
|
||||
//
|
||||
this.OptionsMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@ -1193,7 +1217,7 @@
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(733, 547);
|
||||
this.ClientSize = new System.Drawing.Size(733, 585);
|
||||
this.Controls.Add(this.MainSplitContainer);
|
||||
this.Controls.Add(this.MainMenu);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
@ -1291,6 +1315,7 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem EditMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem EditNewLightMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem EditDeleteLightMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem EditDuplicateLightMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem OptionsMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem OptionsShowOutlinesMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem MoveMenuItem;
|
||||
@ -1319,5 +1344,6 @@
|
||||
private System.Windows.Forms.NumericUpDown FlashinessUpDown;
|
||||
private System.Windows.Forms.Button DeleteLightButton;
|
||||
private System.Windows.Forms.Button NewLightButton;
|
||||
private System.Windows.Forms.Button DuplicateLightButton;
|
||||
}
|
||||
}
|
@ -111,6 +111,7 @@ namespace CodeWalker.Forms
|
||||
{
|
||||
DeleteLightButton.Enabled = false;
|
||||
EditDeleteLightMenu.Enabled = false;
|
||||
EditDuplicateLightMenu.Enabled = false;
|
||||
populatingui = true;
|
||||
PositionTextBox.Text = "";
|
||||
DirectionTextBox.Text = "";
|
||||
@ -154,6 +155,7 @@ namespace CodeWalker.Forms
|
||||
{
|
||||
DeleteLightButton.Enabled = true;
|
||||
EditDeleteLightMenu.Enabled = true;
|
||||
EditDuplicateLightMenu.Enabled = true;
|
||||
populatingui = true;
|
||||
PositionTextBox.Text = FloatUtil.GetVector3String(light.Position);
|
||||
DirectionTextBox.Text = FloatUtil.GetVector3String(light.Direction);
|
||||
@ -222,6 +224,57 @@ namespace CodeWalker.Forms
|
||||
light.TimeFlags = 14680191;
|
||||
return light;
|
||||
}
|
||||
private LightAttributes DuplicateLightAttribute()
|
||||
{
|
||||
LightAttributes light = new LightAttributes();
|
||||
light.Unknown_0h = selectedLight.Unknown_0h;
|
||||
light.Unknown_4h = selectedLight.Unknown_4h;
|
||||
light.Position = selectedLight.Position;
|
||||
light.Unknown_14h = selectedLight.Unknown_14h;
|
||||
light.ColorR = selectedLight.ColorR;
|
||||
light.ColorG = selectedLight.ColorG;
|
||||
light.ColorB = selectedLight.ColorB;
|
||||
light.Flashiness = selectedLight.Flashiness;
|
||||
light.Intensity = selectedLight.Intensity;
|
||||
light.Flags = selectedLight.Flags;
|
||||
light.BoneId = selectedLight.BoneId;
|
||||
light.Type = selectedLight.Type;
|
||||
light.GroupId = selectedLight.GroupId;
|
||||
light.TimeFlags = selectedLight.TimeFlags;
|
||||
light.Falloff = selectedLight.Falloff;
|
||||
light.FalloffExponent = selectedLight.FalloffExponent;
|
||||
light.CullingPlaneNormal = selectedLight.CullingPlaneNormal;
|
||||
light.CullingPlaneOffset = selectedLight.CullingPlaneOffset;
|
||||
light.ShadowBlur = selectedLight.ShadowBlur;
|
||||
light.Unknown_45h = selectedLight.Unknown_45h;
|
||||
light.Unknown_46h = selectedLight.Unknown_46h;
|
||||
light.VolumeIntensity = selectedLight.VolumeIntensity;
|
||||
light.VolumeSizeScale = selectedLight.VolumeSizeScale;
|
||||
light.VolumeOuterColorR = selectedLight.VolumeOuterColorR;
|
||||
light.VolumeOuterColorG = selectedLight.VolumeOuterColorG;
|
||||
light.VolumeOuterColorB = selectedLight.VolumeOuterColorB;
|
||||
light.LightHash = selectedLight.LightHash;
|
||||
light.VolumeOuterIntensity = selectedLight.VolumeOuterIntensity;
|
||||
light.CoronaSize = selectedLight.CoronaSize;
|
||||
light.VolumeOuterExponent = selectedLight.VolumeOuterExponent;
|
||||
light.LightFadeDistance = selectedLight.LightFadeDistance;
|
||||
light.ShadowFadeDistance = selectedLight.ShadowFadeDistance;
|
||||
light.SpecularFadeDistance = selectedLight.SpecularFadeDistance;
|
||||
light.VolumetricFadeDistance = selectedLight.VolumetricFadeDistance;
|
||||
light.ShadowNearClip = selectedLight.ShadowNearClip;
|
||||
light.CoronaIntensity = selectedLight.CoronaIntensity;
|
||||
light.CoronaZBias = selectedLight.CoronaZBias;
|
||||
light.Direction = selectedLight.Direction;
|
||||
light.Tangent = selectedLight.Tangent;
|
||||
light.ConeInnerAngle = selectedLight.ConeInnerAngle;
|
||||
light.ConeOuterAngle = selectedLight.ConeOuterAngle;
|
||||
light.Extent = selectedLight.Extent;
|
||||
light.ProjectedTextureHash = selectedLight.ProjectedTextureHash;
|
||||
light.Unknown_A4h = selectedLight.Unknown_A4h;
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
private void SelectLight(LightAttributes light)
|
||||
{
|
||||
if (light == null)
|
||||
@ -318,7 +371,7 @@ namespace CodeWalker.Forms
|
||||
private void DeleteLight()
|
||||
{
|
||||
if (selectedLight == null) return;
|
||||
if(Drawable != null)
|
||||
if (Drawable != null)
|
||||
{
|
||||
List<LightAttributes> lights = Drawable.LightAttributes.data_items.ToList();
|
||||
lights.Remove(selectedLight);
|
||||
@ -346,6 +399,50 @@ namespace CodeWalker.Forms
|
||||
LoadModels(DrawableDict);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DuplicateLight()
|
||||
{
|
||||
if (selectedLight == null) return;
|
||||
selectedLight = DuplicateLightAttribute();
|
||||
if (Drawable != null)
|
||||
{
|
||||
if (Drawable.LightAttributes == null) Drawable.LightAttributes = new ResourceSimpleList64<LightAttributes>();
|
||||
List<LightAttributes> lights = Drawable.LightAttributes.data_items?.ToList() ?? new List<LightAttributes>();
|
||||
lights.Add(selectedLight);
|
||||
Drawable.LightAttributes.data_items = lights.ToArray();
|
||||
UpdateLightParams();
|
||||
LoadModel(Drawable);
|
||||
}
|
||||
else if (FragDrawable != null)
|
||||
{
|
||||
if (FragDrawable.OwnerFragment.LightAttributes == null) FragDrawable.OwnerFragment.LightAttributes = new ResourceSimpleList64<LightAttributes>();
|
||||
List<LightAttributes> lights = FragDrawable.OwnerFragment.LightAttributes.data_items?.ToList() ?? new List<LightAttributes>();
|
||||
lights.Add(selectedLight);
|
||||
FragDrawable.OwnerFragment.LightAttributes.data_items = lights.ToArray();
|
||||
UpdateLightParams();
|
||||
LoadModel(FragDrawable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var n = LightsTreeView.SelectedNode;
|
||||
if (n != null)
|
||||
{
|
||||
var dr = n.Tag as Drawable;
|
||||
if (dr == null) { dr = n.Parent.Tag as Drawable; } //try parent node tag also
|
||||
if (dr != null)
|
||||
{
|
||||
if (dr.LightAttributes == null) dr.LightAttributes = new ResourceSimpleList64<LightAttributes>();
|
||||
List<LightAttributes> lights = dr.LightAttributes.data_items?.ToList() ?? new List<LightAttributes>();
|
||||
lights.Add(selectedLight);
|
||||
dr.LightAttributes.data_items = lights.ToArray();
|
||||
UpdateLightParams();
|
||||
LoadModels(DrawableDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
SelectLightTreeNode(selectedLight);
|
||||
}
|
||||
|
||||
private void UpdateFlagsCheckBoxes()
|
||||
@ -933,6 +1030,11 @@ namespace CodeWalker.Forms
|
||||
DeleteLight();
|
||||
}
|
||||
|
||||
private void EditDuplicateLightMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
DuplicateLight();
|
||||
}
|
||||
|
||||
private void OptionsShowOutlinesMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
OptionsShowOutlinesMenu.Checked = !OptionsShowOutlinesMenu.Checked;
|
||||
@ -969,5 +1071,15 @@ namespace CodeWalker.Forms
|
||||
{
|
||||
DeleteLight();
|
||||
}
|
||||
|
||||
private void DuplicateLightButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
DuplicateLight();
|
||||
}
|
||||
|
||||
private void MainSplitContainer_Panel2_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -432,8 +432,25 @@ namespace CodeWalker.Utils
|
||||
a[i] = Lerp(a[i], min, max);
|
||||
}
|
||||
break;
|
||||
//case Dat10Synth.Opcode.LERP_BUFFER_2:
|
||||
// break;
|
||||
case Dat10Synth.Opcode.LERP_BUFFER_2: // TODO: some better name for LERP_BUFFER_2
|
||||
{
|
||||
var t = GetScalar(param[1]);
|
||||
float[] min, max;
|
||||
if ((param[0].Value & 0xFF) == (param[2].Value & 0xFF))
|
||||
{
|
||||
min = GetBuffer(param[2]);
|
||||
max = GetBuffer(param[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
min = GetBuffer(param[3]);
|
||||
max = GetBuffer(param[2]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
min[i] = Lerp(t, min[i], max[i]);
|
||||
}
|
||||
break;
|
||||
case Dat10Synth.Opcode.LERP_SCALAR:
|
||||
{
|
||||
var t = GetScalar(param[1]);
|
||||
@ -567,18 +584,24 @@ namespace CodeWalker.Utils
|
||||
GetScalar(param[5]),
|
||||
ref StateBlocks[param[6].Value]);
|
||||
break;
|
||||
//case Dat10Synth.Opcode.OnePole_LPF_BUFFER_BUFFER:
|
||||
// break;
|
||||
//case Dat10Synth.Opcode.OnePole_LPF_BUFFER_SCALAR:
|
||||
// break;
|
||||
//case Dat10Synth.Opcode.OnePole_LPF_SCALAR_SCALAR:
|
||||
// break;
|
||||
//case Dat10Synth.Opcode.OnePole_HPF_BUFFER_BUFFER:
|
||||
// break;
|
||||
//case Dat10Synth.Opcode.OnePole_HPF_BUFFER_SCALAR:
|
||||
// break;
|
||||
//case Dat10Synth.Opcode.OnePole_HPF_SCALAR_SCALAR:
|
||||
// break;
|
||||
case Dat10Synth.Opcode.OnePole_LPF_BUFFER_BUFFER:
|
||||
OnePoleLPF(GetBuffer(param[0]), GetBuffer(param[1]), ref StateBlocks[param[2].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.OnePole_LPF_BUFFER_SCALAR:
|
||||
OnePoleLPF(GetBuffer(param[0]), GetScalar(param[1]), ref StateBlocks[param[2].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.OnePole_LPF_SCALAR_SCALAR:
|
||||
SetRegister(param[0], OnePoleLPF(GetScalar(param[1]), GetScalar(param[2]), ref StateBlocks[param[3].Value]));
|
||||
break;
|
||||
case Dat10Synth.Opcode.OnePole_HPF_BUFFER_BUFFER:
|
||||
OnePoleHPF(GetBuffer(param[0]), GetBuffer(param[1]), ref StateBlocks[param[2].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.OnePole_HPF_BUFFER_SCALAR:
|
||||
OnePoleHPF(GetBuffer(param[0]), GetScalar(param[1]), ref StateBlocks[param[2].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.OnePole_HPF_SCALAR_SCALAR:
|
||||
SetRegister(param[0], OnePoleHPF(GetScalar(param[1]), GetScalar(param[2]), ref StateBlocks[param[3].Value]));
|
||||
break;
|
||||
case Dat10Synth.Opcode.OSC_RAMP_BUFFER_BUFFER:
|
||||
OscillatorRamp(GetBuffer(param[0]), ref StateBlocks[param[1].Value]);
|
||||
break;
|
||||
@ -816,8 +839,9 @@ namespace CodeWalker.Utils
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
a[i] = scalar;
|
||||
break;
|
||||
//case Dat10Synth.Opcode.AWProcess:
|
||||
// break;
|
||||
case Dat10Synth.Opcode.AWProcess:
|
||||
AWFilter(GetBuffer(param[0]), GetBuffer(param[1]), GetBuffer(param[2]), ref StateBlocks[param[3].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.LERP_BUFFER_BUFFER:
|
||||
{
|
||||
var t = GetBuffer(param[0]);
|
||||
@ -910,10 +934,12 @@ namespace CodeWalker.Utils
|
||||
SetRegister(param[0], result);
|
||||
}
|
||||
break;
|
||||
//case Dat10Synth.Opcode.AllpassProcess_BUFFER_SCALAR:
|
||||
// break;
|
||||
//case Dat10Synth.Opcode.AllpassProcess_BUFFER_BUFFER:
|
||||
// break;
|
||||
case Dat10Synth.Opcode.AllpassProcess_BUFFER_SCALAR:
|
||||
AllpassFilter(GetBuffer(param[0]), GetScalar(param[1]), ref StateBlocks[param[2].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.AllpassProcess_BUFFER_BUFFER:
|
||||
AllpassFilter(GetBuffer(param[0]), GetBuffer(param[1]), ref StateBlocks[param[2].Value]);
|
||||
break;
|
||||
case Dat10Synth.Opcode.FINISH:
|
||||
frameFinished = true;
|
||||
break;
|
||||
@ -1007,32 +1033,19 @@ namespace CodeWalker.Utils
|
||||
return (max - min) * t + min;
|
||||
}
|
||||
|
||||
private float HardKnee(float y, float threshold)
|
||||
private float HardKnee(float sample, float threshold)
|
||||
{
|
||||
/*
|
||||
ENVELOPE_GEN__R_LINEAR_T_ONE_SHOT 0, 0.025, 0, 1, 0, 0, 1 => B0 [0]
|
||||
COPY_BUFFER B0 => B1
|
||||
HARD_KNEE_BUFFER B1, 0.25 => B1
|
||||
COPY_BUFFER B0 => B2
|
||||
HARD_KNEE_BUFFER B2, 0.85 => B2
|
||||
COPY_BUFFER B0 => B4
|
||||
HARD_KNEE_BUFFER B4, 0.75 => B4
|
||||
|
||||
FILL_BUFFER 0 => B3
|
||||
FINISH =>
|
||||
*/
|
||||
// TODO(alexguirre): better names for HardKnee and maybe some comments
|
||||
float result;
|
||||
|
||||
if (y < 0.0f)
|
||||
if (sample < 0.0f)
|
||||
result = 0.0f;
|
||||
else
|
||||
result = (y / threshold) * 0.5f;
|
||||
result = (sample / threshold) * 0.5f;
|
||||
|
||||
if ((y - threshold) >= 0.0f)
|
||||
result = (((y - threshold) / (1.0f - threshold)) + 1.0f) * 0.5f;
|
||||
if (sample >= threshold)
|
||||
result = (((sample - threshold) / (1.0f - threshold)) + 1.0f) * 0.5f;
|
||||
|
||||
if (y >= 1.0f)
|
||||
if (sample >= 1.0f)
|
||||
result = 1.0f;
|
||||
|
||||
return result;
|
||||
@ -1048,10 +1061,11 @@ FINISH =>
|
||||
return (float)Math.Pow(Math.Max(0, a), b);
|
||||
}
|
||||
|
||||
private float NoteToFrequency(float note)
|
||||
// https://newt.phys.unsw.edu.au/jw/notes.html
|
||||
private float NoteToFrequency(float midiNote)
|
||||
{
|
||||
// TODO(alexguirre): figure out the meaning of this formula and constants in NoteToFrequency
|
||||
return (float)Math.Pow(2.0f, (note + 36.376301f) / 12.0f);
|
||||
// A4 (note #69) = 440Hz
|
||||
return 440.0f * (float)Math.Pow(2.0f, (midiNote - 69) / 12.0f);
|
||||
}
|
||||
|
||||
private void Decimate(float[] buffer, float scalar1, float deltaPerSample, ref StateBlock stateBlock)
|
||||
@ -1220,7 +1234,7 @@ FINISH =>
|
||||
|
||||
float w = (float)(2.0 * Math.PI * centerFrequency / SampleRate);
|
||||
float cosW = (float)Math.Cos(w);
|
||||
float v14 = 1.0f / (float)Math.Tan((freq2 * 0.000020833333f) * Math.PI);
|
||||
float v14 = 1.0f / (float)Math.Tan(Math.PI * freq2 / SampleRate);
|
||||
|
||||
b0 = 1.0f;
|
||||
b1 = 0.0f;
|
||||
@ -1243,7 +1257,7 @@ FINISH =>
|
||||
|
||||
float w = (float)(2.0f * Math.PI * centerFrequency / SampleRate);
|
||||
float cosW = (float)Math.Cos(w);
|
||||
float v15 = (float)Math.Tan((freq2 * 0.000020833333f) * Math.PI);
|
||||
float v15 = (float)Math.Tan(Math.PI * freq2 / SampleRate);
|
||||
|
||||
b0 = 1.0f;
|
||||
b1 = -2.0f * cosW;
|
||||
@ -1268,7 +1282,7 @@ FINISH =>
|
||||
float q = centerFrequency / freq2;
|
||||
float alpha = (float)Math.Sin(w) / (2.0f * q);
|
||||
float cosW = (float)Math.Cos(w);
|
||||
float A = Math.Max(0.000001f, gain * 1.4141999f); // TODO(alexguirre): this should be amp = 10.0 ** (gain_db/40.0), where does 1.41 come from? maybe gain not in dB?
|
||||
float A = Math.Max(0.000001f, gain * (float)Math.Sqrt(2)); // TODO(alexguirre): this should be amp = 10.0 ** (gain_db/40.0), where does sqrt(2) come from? maybe gain not in dB?
|
||||
|
||||
b0 = 1.0f + alpha * A;
|
||||
b1 = -2.0f * cosW;
|
||||
@ -1338,53 +1352,96 @@ FINISH =>
|
||||
|
||||
private void BiquadFilter2Pole(float[] buffer, float b0, float b1, float b2, float a1, float a2, ref StateBlock stateBlock)
|
||||
{
|
||||
// State block:
|
||||
// X -> ...
|
||||
// Y -> ...
|
||||
|
||||
float stateX = stateBlock.X;
|
||||
float stateY = stateBlock.Y;
|
||||
float pole1 = stateBlock.X;
|
||||
float pole2 = stateBlock.Y;
|
||||
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
float x = (buffer[i] * b0) + stateX;
|
||||
stateX = (buffer[i] * b1) - (x * a1) + stateY;
|
||||
stateY = (buffer[i] * b2) - (x * a2);
|
||||
float s = buffer[i];
|
||||
float x = (s * b0) + pole1;
|
||||
pole1 = (s * b1) - (x * a1) + pole2;
|
||||
pole2 = (s * b2) - (x * a2);
|
||||
buffer[i] = x;
|
||||
}
|
||||
|
||||
stateBlock.X = stateX;
|
||||
stateBlock.Y = stateY;
|
||||
stateBlock.X = pole1;
|
||||
stateBlock.Y = pole2;
|
||||
}
|
||||
|
||||
private void BiquadFilter4Pole(float[] buffer, float b0, float b1, float b2, float a1, float a2, ref StateBlock stateBlock)
|
||||
{
|
||||
// State block:
|
||||
// X -> ...
|
||||
// Y -> ...
|
||||
// Z -> ...
|
||||
// W -> ...
|
||||
|
||||
float stateX = stateBlock.X;
|
||||
float stateY = stateBlock.Y;
|
||||
float stateZ = stateBlock.Z;
|
||||
float stateW = stateBlock.W;
|
||||
float pole1 = stateBlock.X;
|
||||
float pole2 = stateBlock.Y;
|
||||
float pole3 = stateBlock.Z;
|
||||
float pole4 = stateBlock.W;
|
||||
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
float x = (buffer[i] * b0) + stateX;
|
||||
float y = (x * b0) + stateZ;
|
||||
stateX = (buffer[i] * b1) - (x * a1) + stateY;
|
||||
stateY = (buffer[i] * b2) - (x * a2);
|
||||
stateZ = (x * b1) - (y * a1) + stateW;
|
||||
stateW = (x * b2) - (y * a2);
|
||||
float s = buffer[i];
|
||||
float x = (s * b0) + pole1;
|
||||
pole1 = (s * b1) - (x * a1) + pole2;
|
||||
pole2 = (s * b2) - (x * a2);
|
||||
float y = (x * b0) + pole3;
|
||||
pole3 = (x * b1) - (y * a1) + pole4;
|
||||
pole4 = (x * b2) - (y * a2);
|
||||
buffer[i] = y;
|
||||
}
|
||||
|
||||
stateBlock.X = stateX;
|
||||
stateBlock.Y = stateY;
|
||||
stateBlock.Z = stateZ;
|
||||
stateBlock.W = stateW;
|
||||
stateBlock.X = pole1;
|
||||
stateBlock.Y = pole2;
|
||||
stateBlock.Z = pole3;
|
||||
stateBlock.W = pole4;
|
||||
}
|
||||
|
||||
// https://www.earlevel.com/main/2012/12/15/a-one-pole-filter/
|
||||
// TODO: verify OnePoleLPF/HPF results
|
||||
private void OnePoleLPF(float[] buffer, float[] frequencies, ref StateBlock stateBlock)
|
||||
{
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
buffer[i] = OnePoleLPF(buffer[i], frequencies[i], ref stateBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnePoleLPF(float[] buffer, float frequency, ref StateBlock stateBlock)
|
||||
{
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
buffer[i] = OnePoleLPF(buffer[i], frequency, ref stateBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private float OnePoleLPF(float sample, float frequency, ref StateBlock stateBlock)
|
||||
{
|
||||
float previousSample = stateBlock.X;
|
||||
|
||||
float b1 = (float)Math.Exp(-2.0f * Math.PI * frequency * 256.0f / SampleRate);
|
||||
float a0 = 1.0f - b1;
|
||||
|
||||
float s = a0 * sample + (b1 * previousSample);
|
||||
stateBlock.X = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
private void OnePoleHPF(float[] buffer, float[] frequencies, ref StateBlock stateBlock)
|
||||
{
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
buffer[i] = OnePoleHPF(buffer[i], frequencies[i], ref stateBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnePoleHPF(float[] buffer, float frequency, ref StateBlock stateBlock)
|
||||
{
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
buffer[i] = OnePoleHPF(buffer[i], frequency, ref stateBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private float OnePoleHPF(float sample, float frequency, ref StateBlock stateBlock)
|
||||
{
|
||||
return sample - OnePoleLPF(sample, frequency, ref stateBlock);
|
||||
}
|
||||
|
||||
private void EnvelopeFollower(float[] buffer, float a2, float a3, ref StateBlock stateBlock)
|
||||
@ -1469,13 +1526,12 @@ FINISH =>
|
||||
// State block:
|
||||
// X -> latch SET
|
||||
|
||||
// TODO(alexguirre): understand logic of TriggerLatch
|
||||
float stateSet = stateBlock.X;
|
||||
bool set = stateBlock.X != 0.0f;
|
||||
float latch = 0.0f;
|
||||
if (triggered && stateSet == 0.0f)
|
||||
if (triggered && !set)
|
||||
latch = 1.0f;
|
||||
|
||||
if (triggered != (stateSet != 0.0f))
|
||||
if (triggered != set)
|
||||
{
|
||||
stateBlock.X = triggered ? 1.0f : 0.0f;
|
||||
}
|
||||
@ -1811,21 +1867,6 @@ FINISH =>
|
||||
|
||||
// TODO(alexguirre): TimedTrigger may not be equivalent, game code has like 10 states, here I'm using the same states as the envelope gen
|
||||
// TODO(alexguirre): verify how TimedTrigger works in-game
|
||||
/*
|
||||
ENVELOPE_GEN__R_LINEAR_T_ONE_SHOT 0.1, 0.2, 0.3, 0.5, 0.4, 0.35, 1 => B6, R0 [1]
|
||||
TIMED_TRIGGER__T_ONE_SHOT 1, 0.1, 0.2, 0.3, 0.4, 0.35 => R1, R2, R3, R4, R5 [2]
|
||||
|
||||
;FILL_BUFFER R0 => B0 ; envelope finished
|
||||
FILL_BUFFER R1 => B1 ; timed trigger finished
|
||||
;FILL_BUFFER R2 => B2 ; attack
|
||||
;FILL_BUFFER R3 => B3 ; decay
|
||||
;FILL_BUFFER R4 => B4 ; hold
|
||||
;FILL_BUFFER R5 => B5 ; release
|
||||
|
||||
|
||||
FILL_BUFFER 0 => B7
|
||||
FINISH =>
|
||||
*/
|
||||
private TimedTriggerResult TimedTrigger(EnvelopeTriggerMode triggerMode, ref StateBlock stateBlock, float trigger, float predelay, float attack, float decay, float hold, float release)
|
||||
{
|
||||
// State block:
|
||||
@ -2070,6 +2111,65 @@ FINISH =>
|
||||
}
|
||||
}
|
||||
|
||||
private void AWFilter(float[] buffer, float[] buffer2, float[] buffer3, ref StateBlock stateBlock)
|
||||
{
|
||||
var s = stateBlock.X;
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
var v10 = buffer3[i] * 64.0f;
|
||||
var v12 = (float)rnd.NextDouble() * v10 + buffer2[i] * 127.0f + 1.0f;
|
||||
var v13 = 1.0f / v12;
|
||||
var v14 = (1.0f - (v13 * v12)) * v13 + v13;
|
||||
s = s - ((s - buffer[i]) * v14);
|
||||
buffer[i] = s;
|
||||
}
|
||||
stateBlock.X = s;
|
||||
}
|
||||
|
||||
// https://thewolfsound.com/allpass-filter/#first-order-iir-allpass
|
||||
private void AllpassFilter(float[] buffer, float breakFrequency, ref StateBlock stateBlock)
|
||||
{
|
||||
float previousUnfilteredSample = stateBlock.X;
|
||||
float previousSample = stateBlock.Y;
|
||||
|
||||
float a1 = (float)Math.Tan(Math.PI * breakFrequency / SampleRate);
|
||||
a1 = (a1 - 1.0f) / (a1 + 1.0f);
|
||||
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
float sample = a1 * buffer[i] + previousUnfilteredSample - a1 * previousSample;
|
||||
sample = Math.Max(Math.Min(sample, 1.0f), -1.0f);
|
||||
|
||||
previousUnfilteredSample = buffer[i];
|
||||
previousSample = sample;
|
||||
buffer[i] = sample;
|
||||
}
|
||||
|
||||
stateBlock.X = previousUnfilteredSample;
|
||||
stateBlock.Y = previousSample;
|
||||
}
|
||||
|
||||
private void AllpassFilter(float[] buffer, float[] breakFrequencies, ref StateBlock stateBlock)
|
||||
{
|
||||
float previousUnfilteredSample = stateBlock.X;
|
||||
float previousSample = stateBlock.Y;
|
||||
|
||||
for (int i = 0; i < BufferSize; i++)
|
||||
{
|
||||
float a1 = (float)Math.Tan(Math.PI * breakFrequencies[i] / SampleRate);
|
||||
a1 = (a1 - 1.0f) / (a1 + 1.0f);
|
||||
|
||||
float sample = a1 * buffer[i] + previousUnfilteredSample - a1 * previousSample;
|
||||
sample = Math.Max(Math.Min(sample, 1.0f), -1.0f);
|
||||
|
||||
previousUnfilteredSample = buffer[i];
|
||||
previousSample = sample;
|
||||
buffer[i] = sample;
|
||||
}
|
||||
|
||||
stateBlock.X = previousUnfilteredSample;
|
||||
stateBlock.Y = previousSample;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user