diff --git a/Fushigi.Bfres/Common/SubStream.cs b/Fushigi.Bfres/Common/SubStream.cs
new file mode 100644
index 00000000..f6657cfe
--- /dev/null
+++ b/Fushigi.Bfres/Common/SubStream.cs
@@ -0,0 +1,81 @@
+using System;
+using System.IO;
+
+namespace Fushigi
+{
+ //From
+ //https://github.com/IcySon55/Kuriimu/blob/master/src/Kontract/IO/SubStream.cs
+
+ ///
+ /// Represenents a stream taked from another given an offset and length
+ /// Used for archives with streams left open
+ ///
+ public class SubStream : Stream
+ {
+ Stream baseStream;
+ readonly long length;
+ readonly long baseOffset;
+ public SubStream(Stream baseStream, long offset, long length)
+ {
+ if (baseStream == null) throw new ArgumentNullException("baseStream");
+ if (!baseStream.CanRead) throw new ArgumentException("baseStream.CanRead is false");
+ if (!baseStream.CanSeek) throw new ArgumentException("baseStream.CanSeek is false");
+ if (offset < 0) throw new ArgumentOutOfRangeException("offset");
+ if (offset + length > baseStream.Length) throw new ArgumentOutOfRangeException("length");
+
+ this.baseStream = baseStream;
+ this.length = length;
+ baseOffset = offset;
+ }
+
+ public SubStream(Stream baseStream, long offset)
+ {
+ long length = baseStream.Length - offset;
+
+ if (baseStream == null) throw new ArgumentNullException("baseStream");
+ if (!baseStream.CanRead) throw new ArgumentException("baseStream.CanRead is false");
+ if (!baseStream.CanSeek) throw new ArgumentException("baseStream.CanSeek is false");
+ if (offset < 0) throw new ArgumentOutOfRangeException("offset");
+ if (offset + length > baseStream.Length) throw new ArgumentOutOfRangeException("length");
+
+ this.baseStream = baseStream;
+ this.length = length;
+ baseOffset = offset;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ baseStream.Position = baseOffset + offset + Position;
+ int read = baseStream.Read(buffer, offset, (int)Math.Min(count, length - Position));
+ Position += read;
+ return read;
+ }
+
+ public override long Length => length;
+ public override bool CanRead => true;
+ public override bool CanWrite => false;
+ public override bool CanSeek => true;
+ public override long Position { get; set; }
+ public override void Flush() => baseStream.Flush();
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ switch (origin)
+ {
+ case SeekOrigin.Begin: return Position = offset;
+ case SeekOrigin.Current: return Position += offset;
+ case SeekOrigin.End: return Position = length + offset;
+ }
+ throw new ArgumentException("origin is invalid");
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fushigi.Bfres/ExternalLibraries/Ryujinx.Graphics.Shader.dll b/Fushigi.Bfres/ExternalLibraries/Ryujinx.Graphics.Shader.dll
new file mode 100644
index 00000000..066388e1
Binary files /dev/null and b/Fushigi.Bfres/ExternalLibraries/Ryujinx.Graphics.Shader.dll differ
diff --git a/Fushigi.Bfres/ExternalLibraries/Spv.Generator.dll b/Fushigi.Bfres/ExternalLibraries/Spv.Generator.dll
new file mode 100644
index 00000000..d2b22b9c
Binary files /dev/null and b/Fushigi.Bfres/ExternalLibraries/Spv.Generator.dll differ
diff --git a/Fushigi.Bfres/Shaders/BfshaFile.cs b/Fushigi.Bfres/Shaders/BfshaFile.cs
index bc2aa3ae..7670d4b1 100644
--- a/Fushigi.Bfres/Shaders/BfshaFile.cs
+++ b/Fushigi.Bfres/Shaders/BfshaFile.cs
@@ -1,16 +1,5 @@
using Fushigi.Bfres.Common;
-using Ryujinx.Common.Logging;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection.PortableExecutable;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-using static Fushigi.Bfres.BfshaFile;
-using static System.Runtime.InteropServices.JavaScript.JSType;
+
namespace Fushigi.Bfres
{
@@ -69,8 +58,12 @@ public class ShaderModel : IResData
private ShaderModelHeader header;
+ private Stream Stream;
+
public void Read(BinaryReader reader)
{
+ Stream = reader.BaseStream;
+
reader.BaseStream.Read(Utils.AsSpan(ref header));
long pos = reader.BaseStream.Position;
@@ -110,22 +103,21 @@ public void Read(BinaryReader reader)
reader.SeekBegin((long)header.BnshOffset + 0x1C);
var bnshSize = (int)reader.ReadUInt32();
- reader.SeekBegin((long)header.BnshOffset);
- byte[] data = reader.ReadBytes(bnshSize);
- BnshFile = new BnshFile(new MemoryStream(data));
-
reader.SeekBegin(pos);
}
public BnshFile.ShaderVariation GetShaderVariation(ShaderProgram program)
{
- foreach (var var in BnshFile.Variations)
- {
- //Todo this is kinda dumb. It would be better if I read the variation from here by offset
- if (var.Position + (long)header.BnshOffset == (long)program.VariationOffset)
- return var;
- }
- return null;
+ Stream.Position = 0;
+
+ var sub = new SubStream(Stream, (long)header.BnshOffset);
+ var reader = sub.AsBinaryReader();
+
+ reader.SeekBegin((long)program.VariationOffset - (long)header.BnshOffset);
+
+ var v = new BnshFile.ShaderVariation();
+ v.Read(reader);
+ return v;
}
public int GetProgramIndex(Dictionary options)
diff --git a/Fushigi.Bfres/Shaders/ShaderUtil.cs b/Fushigi.Bfres/Shaders/ShaderUtil.cs
index 4d31f32f..d571da73 100644
--- a/Fushigi.Bfres/Shaders/ShaderUtil.cs
+++ b/Fushigi.Bfres/Shaders/ShaderUtil.cs
@@ -49,6 +49,8 @@ public static byte[] GenerateShaderParamBuffer(ShaderModel shaderModel, Material
writer.Write((int)matParam.DataValue);
else if (matParam.DataValue is uint)
writer.Write((uint)matParam.DataValue);
+ else if (matParam.DataValue is bool)
+ writer.Write((bool)matParam.DataValue);
else
throw new Exception($"Unsupported render type! {matParam.Type}");
}
diff --git a/Fushigi.Byml/Serializer/BymlSerialize.cs b/Fushigi.Byml/Serializer/BymlSerialize.cs
index 4afc33fa..8e83ec44 100644
--- a/Fushigi.Byml/Serializer/BymlSerialize.cs
+++ b/Fushigi.Byml/Serializer/BymlSerialize.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -132,6 +133,21 @@ static void SetValues(object property, Type type, object section, dynamic value)
SetValue(property, section, dict);
}
+ else if (IsByStringDictionaryType(type, out Type? valueType))
+ {
+ var values = value as BymlHashTable;
+
+
+ var dict = (IDictionary)CreateInstance(type);
+ foreach (var pair in values.Pairs)
+ {
+ var instance = CreateInstance(valueType);
+ Deserialize(instance, pair.Value);
+ dict.Add(pair.Name, instance);
+ }
+
+ SetValue(property, section, dict);
+ }
else
{
var instance = CreateInstance(type);
@@ -143,6 +159,19 @@ static void SetValues(object property, Type type, object section, dynamic value)
SetValue(property, section, value.Data);
}
+ static bool IsByStringDictionaryType(Type type, [NotNullWhen(true)] out Type? valueType)
+ {
+ valueType = null;
+ if(!type.IsGenericType)
+ return false;
+
+ if(!type.GetGenericTypeDefinition().Equals(typeof(Dictionary<,>)))
+ return false;
+
+ valueType = type.GetGenericArguments()[1];
+ return true;
+ }
+
static void SetValue(object property, object instance, object value)
{
if (property is PropertyInfo)